ch.eiafr.cojac.FloatVariablesSorter.java Source code

Java tutorial

Introduction

Here is the source code for ch.eiafr.cojac.FloatVariablesSorter.java

Source

/*
 * *
 *    Copyright 2014 Romain Monnard & Frdric Bapst
 *
 *    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 ch.eiafr.cojac;

import static ch.eiafr.cojac.models.FloatReplacerClasses.*;
import java.util.ArrayList;
import java.util.Arrays;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AnalyzerAdapter;

/**
 * Remap the local variables indices for load & store instructions
 * The FloatVariablesSorter is used to remap the variables defined by the
 * parameters passing for method invocation 
 * It transforms: visitFrame(), visitVarInsn(), visitIinc(), visitLocalVariable()
 */
public class FloatVariablesSorter extends MethodVisitor {
    private final int[] firstFrameMapping;
    private final int maxRenumber;

    public FloatVariablesSorter(int access, String oldDesc, AnalyzerAdapter mv) {
        super(Opcodes.ASM5, mv);
        Type[] args = Type.getArgumentTypes(oldDesc);
        firstFrameMapping = new int[1 + args.length * 2]; // +1 for 'this'
        Arrays.fill(firstFrameMapping, -1); // so that erroneously using unwritten cells will cause problems...
        boolean hasTarget = (Opcodes.ACC_STATIC & access) == 0; // not static -> there is a 'this' param
        int oldVarIndex = 0;
        int newVarIndex = 0;
        int lastIndexSet = -1;
        if (hasTarget) {
            oldVarIndex = newVarIndex = 1;
            firstFrameMapping[0] = 0; // 'this' remains 'this' after remapping...
            lastIndexSet = 0;
        }
        for (Type arg : args) {
            firstFrameMapping[oldVarIndex] = newVarIndex;
            lastIndexSet = oldVarIndex;
            oldVarIndex += arg.getSize();
            newVarIndex += arg.getSize();
            if (arg.equals(Type.DOUBLE_TYPE)) {
                newVarIndex--;
            }
            assert !arg.equals(COJAC_DOUBLE_WRAPPER_TYPE); // this would be strange (the descriptor is the old one)
        }
        maxRenumber = lastIndexSet;
    }

    @Override
    public void visitVarInsn(final int opcode, final int var) {
        mv.visitVarInsn(opcode, remapFirstFrame(var));
    }

    @Override
    public void visitIincInsn(final int var, final int increment) {
        mv.visitIincInsn(remapFirstFrame(var), increment);
    }

    @Override
    public void visitLocalVariable(final String name, final String desc, final String signature, final Label start,
            final Label end, final int index) {
        int newIndex = remapFirstFrame(index);
        mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
    }

    @Override
    public void visitFrame(int type, int nLocal, final Object[] local, int nStack, final Object[] stack) {
        ArrayList<Object> newLocal = new ArrayList<>();
        int nDummySlotsToAdd = 0;
        for (Object object : local) {
            if (object == Opcodes.DOUBLE) {
                newLocal.add(COJAC_DOUBLE_WRAPPER_INTERNAL_NAME);
            } else if (object == Opcodes.FLOAT) {
                newLocal.add(COJAC_FLOAT_WRAPPER_INTERNAL_NAME);
            } else if (object instanceof String && ((String) object).endsWith("[D")) {
                String tab = (String) object;
                tab = tab.replaceAll("D", COJAC_DOUBLE_WRAPPER_TYPE_DESCR);
                newLocal.add(tab);
            } else if (object instanceof String && ((String) object).endsWith("[F")) {
                String tab = (String) object;
                tab = tab.replaceAll("F", COJAC_FLOAT_WRAPPER_TYPE_DESCR);
                newLocal.add(tab);
            } else {
                newLocal.add(object);
            }
        }
        while (nDummySlotsToAdd > 0) {
            newLocal.add(Opcodes.TOP); // or maybe Opcodes.NULL marker?
            nLocal++;
        }

        ArrayList<Object> newStack = new ArrayList<>();
        for (Object object : stack) {
            if (object == Opcodes.DOUBLE) {
                newStack.add(COJAC_DOUBLE_WRAPPER_INTERNAL_NAME);
            } else if (object == Opcodes.FLOAT) {
                newStack.add(COJAC_FLOAT_WRAPPER_INTERNAL_NAME);
            } else if (object instanceof String && ((String) object).endsWith("[D")) {
                String tab = (String) object;
                tab = tab.replaceAll("D", COJAC_DOUBLE_WRAPPER_TYPE_DESCR);
                newStack.add(tab);
            } else if (object instanceof String && ((String) object).endsWith("[F")) {
                String tab = (String) object;
                tab = tab.replaceAll("F", COJAC_FLOAT_WRAPPER_TYPE_DESCR);
                newStack.add(tab);
            } else {
                newStack.add(object);
            }
        }
        mv.visitFrame(type, nLocal, newLocal.toArray(), nStack, newStack.toArray());
    }

    private int remapFirstFrame(final int var) {
        if (var > maxRenumber) {
            return var;
        }
        return firstFrameMapping[var];
    }
}