Package org.codehaus.groovy.classgen.asm

Source Code of org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher$BinaryShortExpressionHelper

/*
* Copyright 2003-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.classgen.asm;

import java.util.HashMap;
import java.util.Map;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.BinaryExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.classgen.AsmClassGenerator;
import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.StatementMeta;
import org.codehaus.groovy.runtime.BytecodeInterface8;
import org.objectweb.asm.MethodVisitor;

import static org.codehaus.groovy.ast.ClassHelper.*;
import static org.codehaus.groovy.syntax.Types.*;

/**
* This class is for internal use only!
* This class will dispatch to the right type adapters according to the
* kind of binary expression that is provided.
* @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
*/
public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper {

    private static class DummyHelper extends BinaryExpressionWriter {
        public DummyHelper(WriterController controller) {
            super(controller);
        }
        public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
            if (simulate) return false;
            throw new GroovyBugError("should not reach here");
        }
        public boolean write(int operation, boolean simulate) {
            if (simulate) return false;
            throw new GroovyBugError("should not reach here");
        }
        public boolean arrayGet(int operation, boolean simulate) {
            if (simulate) return false;
            throw new GroovyBugError("should not reach here");
        }
        public boolean arraySet(boolean simulate) {
            if (simulate) return false;
            throw new GroovyBugError("should not reach here");
        }
        protected void doubleTwoOperands(MethodVisitor mv) {}
        protected MethodCaller getArrayGetCaller() {
            return null;
        }
        protected MethodCaller getArraySetCaller() {
            return null;
        }
        protected int getBitwiseOperationBytecode(int type) {
            return -1;
        }
        protected int getCompareCode() {
            return -1;
        }
        protected ClassNode getNormalOpResultType() {
            return null;
        }
        protected int getShiftOperationBytecode(int type) {
            return -1;
        }
        protected int getStandardOperationBytecode(int type) {
            return -1;
        }
        protected void removeTwoOperands(MethodVisitor mv) {}
        protected void writePlusPlus(MethodVisitor mv) {}
        protected void writeMinusMinus(MethodVisitor mv) {}
    }
   
    private static class BinaryCharExpressionHelper extends BinaryIntExpressionHelper {
        public BinaryCharExpressionHelper(WriterController wc) {
            super(wc);
        }
        private static final MethodCaller
            charArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "cArrayGet"),
            charArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "cArraySet");
        @Override protected MethodCaller getArrayGetCaller() { return charArrayGet; }
        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.char_TYPE; }
        @Override protected MethodCaller getArraySetCaller() { return charArraySet; }   
    }
   
    private static class BinaryByteExpressionHelper extends BinaryIntExpressionHelper {
        public BinaryByteExpressionHelper(WriterController wc) {
            super(wc);
        }
        private static final MethodCaller
            byteArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "bArrayGet"),
            byteArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "bArraySet");
        @Override protected MethodCaller getArrayGetCaller() { return byteArrayGet; }
        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.byte_TYPE; }
        @Override protected MethodCaller getArraySetCaller() { return byteArraySet; }   
    }
   
    private static class BinaryShortExpressionHelper extends BinaryIntExpressionHelper {
        public BinaryShortExpressionHelper(WriterController wc) {
            super(wc);
        }
        private static final MethodCaller
            shortArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "sArrayGet"),
            shortArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "sArraySet");
        @Override protected MethodCaller getArrayGetCaller() { return shortArrayGet; }
        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.short_TYPE; }
        @Override protected MethodCaller getArraySetCaller() { return shortArraySet; }   
    }
   
    private BinaryExpressionWriter[] binExpWriter = {
            /* 0: dummy  */ new DummyHelper(getController()),
            /* 1: int    */ new BinaryIntExpressionHelper(getController()),
            /* 2: long   */ new BinaryLongExpressionHelper(getController()),
            /* 3: double */ new BinaryDoubleExpressionHelper(getController()),
            /* 4: char   */ new BinaryCharExpressionHelper(getController()),
            /* 5: byte   */ new BinaryByteExpressionHelper(getController()),
            /* 6: short  */ new BinaryShortExpressionHelper(getController()),
            /* 7: float  */ new BinaryFloatExpressionHelper(getController()),
    };
   
    protected static Map<ClassNode,Integer> typeMap = new HashMap<ClassNode,Integer>(14);
    static {
        typeMap.put(int_TYPE,       1); typeMap.put(long_TYPE,      2);
        typeMap.put(double_TYPE,    3); typeMap.put(char_TYPE,      4);
        typeMap.put(byte_TYPE,      5); typeMap.put(short_TYPE,     6);
        typeMap.put(float_TYPE,     7);
    }
    protected final static String[] typeMapKeyNames = {"dummy", "int", "long", "double", "char", "byte", "short", "float"};

    public BinaryExpressionMultiTypeDispatcher(WriterController wc) {
        super(wc);
    }

    /**
     * return the type of an expression, taking meta data into account
     */
    protected static ClassNode getType(Expression exp, ClassNode current) {
        StatementMeta meta = (StatementMeta) exp.getNodeMetaData(StatementMeta.class);
        ClassNode type = null;
        if (meta!=null) type = meta.type;
        if (type!=null) return type;
        if (exp instanceof VariableExpression) {
            VariableExpression ve = (VariableExpression) exp;
            if (ve.isClosureSharedVariable()) return ve.getType();
            type = ve.getOriginType();
            if (ve.getAccessedVariable() instanceof FieldNode) {
                FieldNode fn = (FieldNode) ve.getAccessedVariable();
                if (!fn.getDeclaringClass().equals(current)) return OBJECT_TYPE;
            }
        } else if (exp instanceof Variable) {
            Variable v = (Variable) exp;
            type = v.getOriginType();
        } else {
            type = exp.getType();
        }
        return type.redirect();
    }
   
    protected static boolean isIntCategory(ClassNode type) {
        return  type == int_TYPE    || type == char_TYPE    ||
                type == byte_TYPE   || type == short_TYPE;
    }
   
    protected static boolean isLongCategory(ClassNode type) {
        return  type == long_TYPE   || isIntCategory(type);
    }

    protected static boolean isDoubleCategory(ClassNode type) {
        return  type == float_TYPE  || type == double_TYPE  ||
                isLongCategory(type);
    }
   
    private int getOperandConversionType(ClassNode leftType, ClassNode rightType) {
        if (isIntCategory(leftType) && isIntCategory(rightType)) return 1;
        if (isLongCategory(leftType) && isLongCategory(rightType)) return 2;
        if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) return 3;
        return 0;
    }
   
    private int getOperandType(ClassNode type) {
        Integer ret = typeMap.get(type);
        if (ret==null) return 0;
        return ret;
    }
   
    @Override
    protected void evaluateCompareExpression(final MethodCaller compareMethod, BinaryExpression binExp) {
        ClassNode current =  getController().getClassNode();
        int operation = binExp.getOperation().getType();
       
        Expression leftExp = binExp.getLeftExpression();
        ClassNode leftType = getType(leftExp, current);
        Expression rightExp = binExp.getRightExpression();
        ClassNode rightType = getType(rightExp, current);
       
        int operationType = getOperandConversionType(leftType,rightType);
        BinaryExpressionWriter bew = binExpWriter[operationType];
       
        if (bew.write(operation, true)) {
            AsmClassGenerator acg = getController().getAcg();
            OperandStack os = getController().getOperandStack();
            leftExp.visit(acg);
            os.doGroovyCast(bew.getNormalOpResultType());
            rightExp.visit(acg);
            os.doGroovyCast(bew.getNormalOpResultType());
            bew.write(operation, false);
        } else {
            super.evaluateCompareExpression(compareMethod, binExp);
        }
    }
   
    @Override
    protected void evaluateBinaryExpression(final String message, BinaryExpression binExp) {
        int operation = binExp.getOperation().getType();
        ClassNode current =  getController().getClassNode();

        Expression leftExp = binExp.getLeftExpression();
        ClassNode leftTypeOrig = getType(leftExp, current);
        ClassNode leftType = leftTypeOrig;
        Expression rightExp = binExp.getRightExpression();
        ClassNode rightType = getType(rightExp, current);
        if (operation==LEFT_SQUARE_BRACKET) {
            leftType = leftTypeOrig.getComponentType();
        }

        int operationType = getOperandConversionType(leftType,rightType);
        BinaryExpressionWriter bew = binExpWriter[operationType];
        AsmClassGenerator acg = getController().getAcg();
        OperandStack os = getController().getOperandStack();
       
        if (bew.arrayGet(operation, true)) {
            leftExp.visit(acg);
            os.doGroovyCast(leftTypeOrig);
            rightExp.visit(acg);
            os.doGroovyCast(int_TYPE);
            bew.arrayGet(operation, false);
            os.doGroovyCast(bew.getArrayGetResultType());
        } else if (bew.write(operation, true)) {
            leftExp.visit(acg);
            os.doGroovyCast(bew.getNormalOpResultType());
            rightExp.visit(acg);
            os.doGroovyCast(bew.getNormalOpResultType());
            bew.write(operation, false);
        } else {
            super.evaluateBinaryExpression(message, binExp);
        }
    }
   
    private boolean isAssignmentToArray(BinaryExpression binExp) {
        Expression leftExpression = binExp.getLeftExpression();
        if (!(leftExpression instanceof BinaryExpression)) return false;
        BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
        if (leftBinExpr.getOperation().getType() != LEFT_SQUARE_BRACKET) return false;
        return true;
    }
   
    private int removeAssignment(int op) {
        switch (op) {
            case PLUS_EQUAL: return PLUS;
            case MINUS_EQUAL: return MINUS;
            case MULTIPLY_EQUAL: return MULTIPLY;
            default: return op;
        }
    }
   
    @Override
    protected void evaluateBinaryExpressionWithAssignment(String method, BinaryExpression binExp) {
        if (!isAssignmentToArray(binExp)) {
            super.evaluateBinaryExpressionWithAssignment(method, binExp);
            return;
        }
       
        // we need to handle only assignment to arrays combined with an operation
        // special here. e.g x[a] += b
       
        ClassNode current =  getController().getClassNode();
        int operation = removeAssignment(binExp.getOperation().getType());
       
        Expression leftExp = binExp.getLeftExpression();
        ClassNode leftType = getType(leftExp, current);
        Expression rightExp = binExp.getRightExpression();
        ClassNode rightType = getType(rightExp, current);
       
        int operationType = getOperandConversionType(leftType,rightType);
        BinaryExpressionWriter bew = binExpWriter[operationType];
       
        boolean simulationSuccess = bew.arrayGet(LEFT_SQUARE_BRACKET, true);
        simulationSuccess = simulationSuccess && bew.write(operation, true);
        simulationSuccess = simulationSuccess && bew.arraySet(true);
        if (!simulationSuccess) {
            super.evaluateBinaryExpressionWithAssignment(method, binExp);
            return;
        }
       
        AsmClassGenerator acg = getController().getAcg();
        OperandStack operandStack = getController().getOperandStack();
        CompileStack compileStack = getController().getCompileStack();
              
        // for x[a] += b we have the structure:
        //   x = left(left(binExp))), b = right(binExp), a = right(left(binExp)))
        // for array set we need these values on stack: array, index, right
        // for array get we need these values on stack: array, index
        // to eval the expression we need x[a] = x[a]+b
        // -> arraySet(x,a, x[a]+b)
        // -> arraySet(x,a, arrayGet(x,a,b))
        // --> x,a, x,a, b as operands
        // --> load x, load a, DUP2, call arrayGet, load b, call operation,call arraySet
        // since we cannot DUP2 here easily we will save the subscript and DUP x
        // --> sub=a, load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet
       
        BinaryExpression arrayWithSubscript = (BinaryExpression) leftExp;
        Expression subscript = arrayWithSubscript.getRightExpression();

        // load array index: sub=a [load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet]
        subscript.visit(acg);
        operandStack.doGroovyCast(int_TYPE);
        int subscriptValueId = compileStack.defineTemporaryVariable("$sub", ClassHelper.int_TYPE, true);
       
        // load array: load x and DUP [load sub, call arrayGet, load b, call operation, load sub, call arraySet]
        arrayWithSubscript.getLeftExpression().visit(acg);
        operandStack.dup();
       
        // array get: load sub, call arrayGet [load b, call operation, load sub, call arraySet]
        operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
        bew.arrayGet(LEFT_SQUARE_BRACKET, false);
        operandStack.replace(leftType, 2);
       
        // complete rhs: load b, call operation [load sub, call arraySet]
        binExp.getRightExpression().visit(acg);
        bew.write(operation, false);
       
        // let us save that value for the return
        operandStack.dup();
        int resultValueId = compileStack.defineTemporaryVariable("$result", rightType, true);              

        // array set: load sub, call arraySet []
        operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
        operandStack.swap();
        bew.arraySet(false);
        operandStack.remove(2);

        // load return value
        operandStack.load(rightType, resultValueId);
       
        // cleanup
        compileStack.removeVar(resultValueId);
        compileStack.removeVar(subscriptValueId);
    }
   
    @Override
    protected void assignToArray(Expression orig, Expression receiver, Expression index, Expression rhsValueLoader) {
        ClassNode current = getController().getClassNode();
        ClassNode arrayType = getType(receiver, current);
        ClassNode arrayComponentType = arrayType.getComponentType();
        int operationType = getOperandType(arrayComponentType);
        BinaryExpressionWriter bew = binExpWriter[operationType];
        AsmClassGenerator acg = getController().getAcg();
       
        if (bew.arraySet(true)) {
            OperandStack operandStack   =   getController().getOperandStack();
           
            // load the array
            receiver.visit(acg);
            operandStack.doGroovyCast(arrayType);
           
            // load index
            index.visit(acg);
            operandStack.doGroovyCast(int_TYPE);
           
            // load rhs
            rhsValueLoader.visit(acg);
            operandStack.doGroovyCast(arrayComponentType);
           
            // store value in array
            bew.arraySet(false);
           
            // load return value && correct operand stack stack
            operandStack.remove(3);
            rhsValueLoader.visit(acg);
        } else {       
            super.assignToArray(orig, receiver, index, rhsValueLoader);
        }
    }
   
    @Override
    protected void writePostOrPrefixMethod(int op, String method,  Expression expression, Expression orig) {
        ClassNode type = getType(orig,getController().getClassNode());
        int operationType = getOperandType(type);
        BinaryExpressionWriter bew = binExpWriter[operationType];
        if (bew.writePostOrPrefixMethod(op,true)) {
            OperandStack operandStack   =   getController().getOperandStack();
            // at this point the receiver will be already on the stack
            operandStack.doGroovyCast(type);
            bew.writePostOrPrefixMethod(op,false);
            operandStack.replace(bew.getNormalOpResultType());
        } else {
            super.writePostOrPrefixMethod(op, method, expression, orig);
        }
    }
}
TOP

Related Classes of org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher$BinaryShortExpressionHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.