All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.control.OptimizerVisitor Maven / Gradle / Ivy

There is a newer version: 3.9
Show newest version
/*
 * Copyright 2003-2007 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.control;

import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.objectweb.asm.Opcodes;

import java.util.*;

/**
 * Visitor to produce several optimizations
 *  - to replace numbered constants with references to static fields
 *
 * @author Alex Tkachman
 */
public class OptimizerVisitor extends ClassCodeExpressionTransformer {
    private ClassNode currentClass;
    private SourceUnit source;

    private Map const2Var = new HashMap();
    private List missingFields = new LinkedList();

    public OptimizerVisitor(CompilationUnit cu) {
    }

    public void visitClass(ClassNode node, SourceUnit source) {
        this.currentClass = node;
        this.source = source;
        const2Var.clear();
        missingFields.clear();
        super.visitClass(node);
        addMissingFields();
    }

    private void addMissingFields() {
        for (Object missingField : missingFields) {
            FieldNode f = (FieldNode) missingField;
            currentClass.addField(f);
        }
    }

    private void setConstField(ConstantExpression constantExpression) {
        final Object n = constantExpression.getValue();
        if (!(n instanceof Number || n instanceof Character)) return;
        if (n instanceof Integer || n instanceof Double) return;
        FieldNode field = (FieldNode) const2Var.get(n);
        if (field!=null) {
            constantExpression.setConstantName(field.getName());
            return;
        }
        final String name = "$const$" + const2Var.size();
        //TODO: this part here needs a bit of rethinking. If it can happen that the field is defined already,
        //      then is this code still valid?
        field = currentClass.getDeclaredField(name);
        if (field==null) {
            field = new FieldNode(name,
                    Opcodes.ACC_PRIVATE|Opcodes.ACC_STATIC|Opcodes.ACC_SYNTHETIC| Opcodes.ACC_FINAL,
                    constantExpression.getType(),
                    currentClass,
                    constantExpression
                    );
            field.setSynthetic(true);
            missingFields.add(field);
        }
        constantExpression.setConstantName(field.getName());
        const2Var.put(n, field);
    }

    public Expression transform(Expression exp) {
        if (exp == null) return null;
        if (!currentClass.isInterface() && exp.getClass() == ConstantExpression.class) {
            setConstField((ConstantExpression)exp);
        }
        return exp.transformExpression(this);
    }

    protected SourceUnit getSourceUnit() {
        return source;
    }

    public void visitClosureExpression(ClosureExpression expression) {
        /*
         * GROOVY-3339 - do nothing - so that numbers don't get replaced by cached constants in closure classes
         */
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy