alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Groovy example source code file (OptimizingStatementWriter.java)

This example Groovy source code file (OptimizingStatementWriter.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

classnode, classnode, expression, expressionstatement, fastpathdata, fastpathdata, label, override, override, parameter, returnstatement, statementmeta, statementmeta, string, util

The Groovy OptimizingStatementWriter.java source code

/*
 * 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.LinkedList;

import org.codehaus.groovy.ast.*;
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.classgen.AsmClassGenerator;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.runtime.BytecodeInterface8;
import org.codehaus.groovy.syntax.Types;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;
import static org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher.*;
import static org.codehaus.groovy.ast.ClassHelper.*;

/**
 * 
 * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou
 */
public class OptimizingStatementWriter extends StatementWriter {
    
    private static class FastPathData {
        private Label pathStart = new Label();
        private Label afterPath = new Label();
    }
    
    public static class ClassNodeSkip{}
    
    public static class StatementMeta {
        private boolean optimize=false;
        protected MethodNode target;
        protected ClassNode type;
        protected boolean[] involvedTypes = new boolean[typeMapKeyNames.length];
        public void chainInvolvedTypes(OptimizeFlagsCollector opt) {
            for (int i=0; i<typeMapKeyNames.length; i++) {
                if (opt.current.involvedTypes[i]) {
                    this.involvedTypes[i] = true;
                }
            }
        }
        public String toString() {
            String ret = "optimize="+optimize+" target="+target+" type="+type+" involvedTypes=";
            for (int i=0; i<typeMapKeyNames.length; i++) {
                if (involvedTypes[i]) ret += " "+typeMapKeyNames[i];
            }
            return ret;
        }
    }

    private static MethodCaller[] guards = {
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigInt"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigZ"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigD"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigC"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigB"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigS"),
        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigF"),
    };
    
    private static final MethodCaller disabledStandardMetaClass = MethodCaller.newStatic(BytecodeInterface8.class, "disabledStandardMetaClass");
    private boolean fastPathBlocked = false;
    private WriterController controller;

    public OptimizingStatementWriter(WriterController controller) {
        super(controller);
        this.controller = controller;
    }
    
    private boolean notEnableFastPath(StatementMeta meta) {
        // return false if cannot do fast path and if are already on the path
        return fastPathBlocked || meta==null || !meta.optimize || controller.isFastPath();
    }
    
    private FastPathData writeGuards(StatementMeta meta, Statement statement) {
        if (notEnableFastPath(meta)) return null;
        MethodVisitor mv = controller.getMethodVisitor();
        FastPathData fastPathData = new FastPathData();
        Label slowPath = new Label();
        
        for (int i=0; i<guards.length; i++) {
            if (meta.involvedTypes[i]) {
                guards[i].call(mv);
                mv.visitJumpInsn(IFEQ, slowPath);
            }
        }
        
        // meta class check with boolean holder
        String owner = BytecodeHelper.getClassInternalName(controller.getClassNode());
        MethodNode mn = controller.getMethodNode();
        if (mn!=null) {
            mv.visitFieldInsn(GETSTATIC, owner, Verifier.STATIC_METACLASS_BOOL, "Z");
            mv.visitJumpInsn(IFNE, slowPath);
        }
        
        //standard metaclass check
        disabledStandardMetaClass.call(mv);
        mv.visitJumpInsn(IFNE, slowPath);
        
        // other guards here
        
        mv.visitJumpInsn(GOTO, fastPathData.pathStart);
        mv.visitLabel(slowPath);
        
        return fastPathData;
    }
        
    private void writeFastPathPrelude(FastPathData meta) {
        MethodVisitor mv = controller.getMethodVisitor();
        mv.visitJumpInsn(GOTO, meta.afterPath);
        mv.visitLabel(meta.pathStart);
        controller.switchToFastPath();
    }
    
    private void writeFastPathEpilogue(FastPathData meta) {
        MethodVisitor mv = controller.getMethodVisitor();
        mv.visitLabel(meta.afterPath);
        controller.switchToSlowPath();
    }
    
    @Override
    public void writeBlockStatement(BlockStatement statement) {
        StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
        FastPathData fastPathData = writeGuards(meta, statement);
        
        if (fastPathData==null) {
            // normal mode with different paths
            // important is to not to have a fastpathblock here,
            // otherwise the per expression statement improvement 
            // is impossible
            super.writeBlockStatement(statement);
        } else {
            // fast/slow path generation
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeBlockStatement(statement);
            fastPathBlocked = oldFastPathBlock;
            
            writeFastPathPrelude(fastPathData);
            super.writeBlockStatement(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }
    
    @Override
    public void writeDoWhileLoop(DoWhileStatement statement) {
        if (controller.isFastPath()) {
            super.writeDoWhileLoop(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            FastPathData fastPathData = writeGuards(meta, statement);
    
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeDoWhileLoop(statement);
            fastPathBlocked = oldFastPathBlock;
            
            if (fastPathData==null) return;
            writeFastPathPrelude(fastPathData);
            super.writeDoWhileLoop(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }
    
    @Override
    protected void writeIteratorHasNext(MethodVisitor mv) {
        if (controller.isFastPath()) {
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
        } else {
            super.writeIteratorHasNext(mv);
        }
    }
    
    @Override
    protected void writeIteratorNext(MethodVisitor mv) {
        if (controller.isFastPath()) {
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
        } else {
            super.writeIteratorNext(mv);
        }
    }
    
    @Override
    protected void writeForInLoop(ForStatement statement) {
        if (controller.isFastPath()) {
            super.writeForInLoop(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            FastPathData fastPathData = writeGuards(meta, statement);
    
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeForInLoop(statement);
            fastPathBlocked = oldFastPathBlock;
            
            if (fastPathData==null) return;
            writeFastPathPrelude(fastPathData);
            super.writeForInLoop(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }

    @Override
    protected void writeForLoopWithClosureList(ForStatement statement) {
        if (controller.isFastPath()) {
            super.writeForLoopWithClosureList(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            FastPathData fastPathData = writeGuards(meta, statement);
            
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeForLoopWithClosureList(statement);
            fastPathBlocked = oldFastPathBlock;
            
            if (fastPathData==null) return;
            writeFastPathPrelude(fastPathData);
            super.writeForLoopWithClosureList(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }

    @Override
    public void writeWhileLoop(WhileStatement statement) {
        if (controller.isFastPath()) {
            super.writeWhileLoop(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            FastPathData fastPathData = writeGuards(meta, statement);
            
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeWhileLoop(statement);
            fastPathBlocked = oldFastPathBlock;
            
            if (fastPathData==null) return;
            writeFastPathPrelude(fastPathData);
            super.writeWhileLoop(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }

    @Override
    public void writeIfElse(IfStatement statement) {
        if (controller.isFastPath()) {
            super.writeIfElse(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            FastPathData fastPathData = writeGuards(meta, statement);
            
            boolean oldFastPathBlock = fastPathBlocked;
            fastPathBlocked = true;
            super.writeIfElse(statement);
            fastPathBlocked = oldFastPathBlock;
            
            if (fastPathData==null) return;
            writeFastPathPrelude(fastPathData);
            super.writeIfElse(statement);
            writeFastPathEpilogue(fastPathData);
        }
    }
    
    private boolean isNewPathFork(StatementMeta meta) {
        // meta.optimize -> can do fast path
        if (meta==null || meta.optimize==false) return false;
        // fastPathBlocked -> slow path
        if (fastPathBlocked) return false;
        // controller.isFastPath() -> fastPath
        if (controller.isFastPath()) return false;
        return true;
    }
    
    @Override
    public void writeReturn(ReturnStatement statement) {
        if (controller.isFastPath()) {
            super.writeReturn(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
                FastPathData fastPathData = writeGuards(meta, statement);
                
                boolean oldFastPathBlock = fastPathBlocked;
                fastPathBlocked = true;
                super.writeReturn(statement);
                fastPathBlocked = oldFastPathBlock;
                
                if (fastPathData==null) return;
                writeFastPathPrelude(fastPathData);
                super.writeReturn(statement);
                writeFastPathEpilogue(fastPathData); 
            } else {
                super.writeReturn(statement);
            }
        }
    }

    @Override
    public void writeExpressionStatement(ExpressionStatement statement) {
        if (controller.isFastPath()) {
            super.writeExpressionStatement(statement);
        } else {
            StatementMeta meta = (StatementMeta) statement.getNodeMetaData(StatementMeta.class);
            // we have to have handle DelcarationExpressions special, since their 
            // entry should be outside the optimization path, we have to do that of
            // course only if we are actually going to do two different paths, 
            // otherwise it is not needed
            //
            // there are several cases to be considered now.
            // (1) no fast path possible, so just do super
            // (2) fast path possible, and at path split point (meaning not in 
            //     fast path and not in slow path). Here we have to extract the 
            //     Declaration and replace by an assignment
            // (3) fast path possible and in slow or fastPath. Nothing to do here.
            //
            // the only case we need to handle is then (2).
            
            if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
                FastPathData fastPathData = writeGuards(meta, statement);
                
                boolean oldFastPathBlock = fastPathBlocked;
                fastPathBlocked = true;
                super.writeExpressionStatement(statement);
                fastPathBlocked = oldFastPathBlock;
                
                if (fastPathData==null) return;
                writeFastPathPrelude(fastPathData);
                super.writeExpressionStatement(statement);
                writeFastPathEpilogue(fastPathData);            
            } else {
                super.writeExpressionStatement(statement);
            }
        }
    }

    private boolean writeDeclarationExtraction(Statement statement) {
        Expression ex = null;
        if (statement instanceof ReturnStatement) {
            ReturnStatement rs = (ReturnStatement) statement;
            ex = rs.getExpression();
        } else if (statement instanceof ExpressionStatement) {
            ExpressionStatement es = (ExpressionStatement) statement;
            ex = es.getExpression();            
        } else {
            throw new GroovyBugError("unknown statement type :"+statement.getClass());
        } 
        if (!(ex instanceof DeclarationExpression)) return true;
        DeclarationExpression declaration = (DeclarationExpression) ex;
        ex = declaration.getLeftExpression();
        if (ex instanceof TupleExpression) return false;
                
        // do declaration
        controller.getCompileStack().defineVariable(declaration.getVariableExpression(), false);
        // change statement to do assignment only
        BinaryExpression assignment = new BinaryExpression(
                declaration.getLeftExpression(),
                declaration.getOperation(),
                declaration.getRightExpression());
        assignment.setSourcePosition(declaration);
        assignment.copyNodeMetaData(declaration);
        // replace statement code
        if (statement instanceof ReturnStatement) {
            ReturnStatement rs = (ReturnStatement) statement;
            rs.setExpression(assignment);
        } else if (statement instanceof ExpressionStatement) {
            ExpressionStatement es = (ExpressionStatement) statement;
            es.setExpression(assignment);            
        } else {
            throw new GroovyBugError("unknown statement type :"+statement.getClass());
        }
        return true;
    }
    
    public static void setNodeMeta(ClassNode classNode) {
        if (classNode.getNodeMetaData(ClassNodeSkip.class)!=null) return;
        new OptVisitor().visitClass(classNode);   
    }
    
    private static StatementMeta addMeta(ASTNode node) {
        StatementMeta metaOld = (StatementMeta) node.getNodeMetaData(StatementMeta.class);
        StatementMeta meta = metaOld;
        if (meta==null) meta = new StatementMeta();
        meta.optimize = true;
        if (metaOld==null) node.setNodeMetaData(StatementMeta.class, meta);
        return meta;
    }
    
    private static StatementMeta addMeta(ASTNode node, OptimizeFlagsCollector opt) {
        StatementMeta meta = addMeta(node);
        meta.chainInvolvedTypes(opt);
        return meta;
    }
    
    private static class OptimizeFlagsCollector {
        private static class OptimizeFlagsEntry {
            private boolean canOptimize = false;
            private boolean shouldOptimize = false;
            private boolean[] involvedTypes = new boolean[typeMapKeyNames.length];
        }
        private OptimizeFlagsEntry current = new OptimizeFlagsEntry();
        private LinkedList<OptimizeFlagsEntry> olderEntries = new LinkedList();
        public void push() {
            olderEntries.addLast(current);
            current = new OptimizeFlagsEntry();
        }
        public void pop(boolean propagateFlags){
            OptimizeFlagsEntry old = current;
            current = olderEntries.removeLast();
            if (propagateFlags) {
                chainCanOptimize(old.canOptimize);
                chainShouldOptimize(old.shouldOptimize);
                for (int i=0; i<typeMapKeyNames.length; i++) current.involvedTypes[i] |= old.involvedTypes[i];
            }
        }
        public String toString() {
            String ret = "";
            if (current.shouldOptimize) {
                ret = "should optimize, can = "+current.canOptimize;
            } else if (current.canOptimize) {
                ret = "can optimize";
            } else {
                ret = "don't optimize";
            }
            ret += " involvedTypes =";
            for (int i=0; i<typeMapKeyNames.length; i++) {
                if (current.involvedTypes[i]) ret += " "+typeMapKeyNames[i];
            }
            return ret;
        }
        /**
         * @return true iff we should Optimize - this is almost seen as must
         */
        private boolean shouldOptimize() {
            return current.shouldOptimize;
        }
        /**
         * @return true iff we can optimize, but not have to
         */
        private boolean canOptimize() {
            return current.canOptimize || current.shouldOptimize;
        }
        /**
         * set "should" to true, if not already
         */
        public void chainShouldOptimize(boolean opt) {
            current.shouldOptimize = shouldOptimize() || opt;
        }
        /**
         * set "can" to true, if not already
         */
        public void chainCanOptimize(boolean opt) {
            current.canOptimize = current.canOptimize || opt;
        }
        public void chainInvolvedType(ClassNode type) {
            Integer res = typeMap.get(type);
            if (res==null) return;
            current.involvedTypes[res] = true;
        }
        public void reset() {
            current.canOptimize = false;
            current.shouldOptimize = false;
            current.involvedTypes = new boolean[typeMapKeyNames.length];
        }
    }
    
    private static class OptVisitor extends ClassCodeVisitorSupport {
        @Override protected SourceUnit getSourceUnit() {return null;}

        private ClassNode node;
        private OptimizeFlagsCollector opt = new OptimizeFlagsCollector();
        private boolean optimizeMethodCall = true;
        
        @Override
        public void visitClass(ClassNode node) {
            this.optimizeMethodCall = !node.implementsInterface(GROOVY_INTERCEPTABLE_TYPE);
            this.node = node;
            super.visitClass(node);
        }
        
        @Override
        public void visitMethod(MethodNode node) {
            super.visitMethod(node);
            opt.reset();
        }
        
        @Override
        public void visitReturnStatement(ReturnStatement statement) {
            opt.push();
            super.visitReturnStatement(statement);
            if (opt.shouldOptimize()) addMeta(statement,opt);
            opt.pop(opt.shouldOptimize());
        }
        
        @Override
        public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
            //TODO: implement int operations for this
            super.visitUnaryMinusExpression(expression);
            StatementMeta meta = addMeta(expression);
            meta.type = OBJECT_TYPE;
        }
        
        @Override
        public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
            //TODO: implement int operations for this
            super.visitUnaryPlusExpression(expression);
            StatementMeta meta = addMeta(expression);
            meta.type = OBJECT_TYPE;
        }
        
        @Override
        public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
            //TODO: implement int operations for this
            super.visitBitwiseNegationExpression(expression);
            StatementMeta meta = addMeta(expression);
            meta.type = OBJECT_TYPE;
        }
        
        private void addTypeInformation(Expression expression, Expression orig) {
            ClassNode type = getType(expression,node);
            if (isPrimitiveType(type)) {
                StatementMeta meta = addMeta(orig);
                meta.type = type;
                opt.chainShouldOptimize(true);
                opt.chainInvolvedType(type);
            }
        }
        
        @Override
        public void visitPrefixExpression(PrefixExpression expression) {
            super.visitPrefixExpression(expression);
            addTypeInformation(expression.getExpression(),expression);
        }
        
        @Override
        public void visitPostfixExpression(PostfixExpression expression) {
            super.visitPostfixExpression(expression);
            addTypeInformation(expression.getExpression(),expression);
        }        
        
        @Override
        public void visitDeclarationExpression(DeclarationExpression expression) {
            Expression right = expression.getRightExpression();
            right.visit(this);
            
            ClassNode leftType = getType(expression.getLeftExpression(),node);
            ClassNode rightType = getType(expression.getRightExpression(),node);
            if (isPrimitiveType(leftType) && isPrimitiveType(rightType)) {
                // if right is a constant, then we optimize only if it makes
                // a block complete, so we set a maybe
                if (right instanceof ConstantExpression) {
                    opt.chainCanOptimize(true);
                } else {
                    opt.chainShouldOptimize(true);
                }
                StatementMeta meta = addMeta(expression);
                meta.type = leftType;
                opt.chainInvolvedType(leftType);
                opt.chainInvolvedType(rightType);
            }
        }
        
        @Override
        public void visitBinaryExpression(BinaryExpression expression) {
            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
            super.visitBinaryExpression(expression);
            
            ClassNode leftType = getType(expression.getLeftExpression(),node);
            ClassNode rightType = getType(expression.getRightExpression(),node);
            ClassNode resultType = null;
            int operation = expression.getOperation().getType();
            
            if (operation==Types.LEFT_SQUARE_BRACKET && leftType.isArray()) {
                opt.chainShouldOptimize(true);
                resultType = leftType.getComponentType();
            } else {
                switch (operation) {
                    case Types.COMPARE_EQUAL: 
                    case Types.COMPARE_LESS_THAN:
                    case Types.COMPARE_LESS_THAN_EQUAL:
                    case Types.COMPARE_GREATER_THAN:
                    case Types.COMPARE_GREATER_THAN_EQUAL:
                    case Types.COMPARE_NOT_EQUAL:
                    case Types.LOGICAL_AND: case Types.LOGICAL_AND_EQUAL:
                    case Types.LOGICAL_OR: case Types.LOGICAL_OR_EQUAL:
                        expression.setType(boolean_TYPE);
                        resultType = boolean_TYPE;
                        break;
                    case Types.DIVIDE: case Types.DIVIDE_EQUAL:
                        if (isLongCategory(leftType) && isLongCategory(rightType)) {
                            //resultType = BigDecimal_TYPE;
                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
                            resultType = double_TYPE;
                        }
                        break;
                    case Types.POWER: case Types.POWER_EQUAL:
                        //TODO: implement
                        break;
                    case Types.ASSIGN:
                        opt.chainCanOptimize(true);
                        break;
                    default:
                        if (isIntCategory(leftType) && isIntCategory(rightType)) {
                            resultType = int_TYPE;
                        } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
                            resultType = long_TYPE;
                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
                            resultType = double_TYPE;
                        }
                }
            }
            
            if (resultType!=null) {
                StatementMeta meta = addMeta(expression);
                meta.type = resultType;
                opt.chainShouldOptimize(true);
                opt.chainInvolvedType(resultType);
                opt.chainInvolvedType(leftType);
                opt.chainInvolvedType(rightType);
            }
        }
        
        @Override
        public void visitExpressionStatement(ExpressionStatement statement) {
            if (statement.getNodeMetaData(StatementMeta.class)!=null) return;
            opt.push();
            super.visitExpressionStatement(statement);
            if (opt.shouldOptimize()) addMeta(statement,opt);
            opt.pop(opt.shouldOptimize());
        }
        
        @Override
        public void visitBlockStatement(BlockStatement block) {
            opt.push();
            boolean optAll = true;
            for (Statement statement : block.getStatements()) {
                opt.push();
                statement.visit(this);
                optAll = optAll && opt.canOptimize();
                opt.pop(true);
            }
            if (block.isEmpty()) {
                opt.chainCanOptimize(true);
                opt.pop(true);
            } else {
                opt.chainShouldOptimize(optAll);                
                if (optAll) addMeta(block,opt);
                opt.pop(optAll);
            }
        }
        
        @Override
        public void visitIfElse(IfStatement statement) {
            opt.push();
            super.visitIfElse(statement);
            if (opt.shouldOptimize()) addMeta(statement,opt);
            opt.pop(opt.shouldOptimize());
        }
        
        @Override
        public void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
            super.visitStaticMethodCallExpression(expression);

            setMethodTarget(expression,expression.getMethod(), expression.getArguments());
        }
        
        @Override
        public void visitMethodCallExpression(MethodCallExpression expression) {
            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
            super.visitMethodCallExpression(expression);
            
            Expression object = expression.getObjectExpression();
            boolean setTarget = AsmClassGenerator.isThisExpression(object);
            if (!setTarget) {
                if (!(object instanceof ClassExpression)) return;
                setTarget = object.equals(node);
            }
            
            if (!setTarget) return;
            setMethodTarget(expression, expression.getMethodAsString(), expression.getArguments());
        }
        
        private void setMethodTarget(Expression expression, String name, Expression callArgs) {
            if (name==null) return;
            if (!optimizeMethodCall) return;
            // find method call target
            Parameter[] paraTypes = null;
            if (callArgs instanceof ArgumentListExpression) {
                ArgumentListExpression args = (ArgumentListExpression) callArgs;
                int size = args.getExpressions().size();
                paraTypes = new Parameter[size];
                int i=0;
                for (Expression exp: args.getExpressions()) {
                    ClassNode type = BinaryExpressionMultiTypeDispatcher.getType(exp,node);
                    if (!validTypeForCall(type)) return;
                    paraTypes[i] = new Parameter(type,"");
                    i++;
                }
            } else {
                ClassNode type = BinaryExpressionMultiTypeDispatcher.getType(callArgs,node);
                paraTypes = new Parameter[]{new Parameter(type,"")};
            }
            
            MethodNode target = node.getMethod(name, paraTypes);
            if (target==null) return;
            if (!target.getDeclaringClass().equals(node)) return;
            StatementMeta meta = addMeta(expression);
            meta.target = target;
            meta.type = target.getReturnType().redirect();
            opt.chainShouldOptimize(true);
        }
        
        private static boolean validTypeForCall(ClassNode type) {
            // do call only for final classes and primitive types
            if (isPrimitiveType(type)) return true;
            if ((type.getModifiers() & ACC_FINAL)>0) return true;
            return false;
        }

        @Override
        public void visitClosureExpression(ClosureExpression expression) {
            return;
        }
        
        @Override
        public void visitForLoop(ForStatement statement) {
            opt.push();
            super.visitForLoop(statement);
            if (opt.shouldOptimize()) addMeta(statement,opt);
            opt.pop(opt.shouldOptimize());
        }
    }
    

}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy OptimizingStatementWriter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.