org.jtsan.LocalVarsSaver.java Source code

Java tutorial

Introduction

Here is the source code for org.jtsan.LocalVarsSaver.java

Source

/* Copyright (c) 2010 Google Inc.
 *
 * 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.jtsan;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.LocalVariablesSorter;

import java.util.ArrayList;

/**
 * Generates bytecode instructions to save method parameters according to their type.
 *
 * @author Egor Pasko
 */
public class LocalVarsSaver {
    private final MethodVisitor mv;
    private final LocalVariablesSorter lvs;
    private ArrayList<Type> types;
    private ArrayList<Integer> vars;
    private boolean hasRetValue;
    private Type returnType;
    private int returnVar;

    public LocalVarsSaver(MethodVisitor mv, LocalVariablesSorter lvs) {
        this.mv = mv;
        this.lvs = lvs;
    }

    public void initFromMethodDesc(String meth) {
        types = parseMethodName(meth);
        vars = newLocalVarsFromTypes(types, lvs);
        if (meth.charAt(meth.length() - 1) != 'V') {
            returnType = Type.getType(meth.substring(meth.indexOf(')') + 1));
            returnVar = lvs.newLocal(returnType);
        }
    }

    public void initFromTypeDesc(String desc) {
        types = new ArrayList<Type>();
        types.add(Type.getType(desc));
        vars = newLocalVarsFromTypes(types, lvs);
    }

    private static ArrayList<Integer> newLocalVarsFromTypes(ArrayList<Type> types, LocalVariablesSorter lvs) {
        ArrayList<Integer> vars = new ArrayList<Integer>();
        for (Type type : types) {
            vars.add(lvs.newLocal(type));
        }
        return vars;
    }

    private static ArrayList<Type> parseMethodName(String meth) {
        ArrayList<Type> types = new ArrayList<Type>();
        int i = meth.indexOf('(') + 1;
        int descEnd = meth.indexOf(')');
        while (i < descEnd) {
            int l = i;
            while (meth.charAt(l) == '[') {
                l++;
            }
            if (meth.charAt(l) == 'L') {
                while (meth.charAt(l) != ';') {
                    l++;
                }
            }
            types.add(Type.getType(meth.substring(i, l + 1)));
            i = l + 1;
        }
        return types;
    }

    public void saveStack() {
        for (int i = types.size() - 1; i >= 0; i--) {
            mv.visitVarInsn(types.get(i).getOpcode(Opcodes.ISTORE), vars.get(i));
        }
    }

    public void loadStack() {
        for (int i = 0; i < types.size(); i++) {
            mv.visitVarInsn(types.get(i).getOpcode(Opcodes.ILOAD), vars.get(i));
        }
    }

    public void saveAndLoadStack() {
        saveStack();
        loadStack();
    }

    public boolean hasReturnValue() {
        return returnType != null;
    }

    public void saveReturnValue() {
        if (!hasReturnValue()) {
            throw new RuntimeException("Return value type is not porperly initialized to be saved.");
        }
        mv.visitVarInsn(returnType.getOpcode(Opcodes.ISTORE), returnVar);
    }

    public void loadReturnValue() {
        if (!hasReturnValue()) {
            throw new RuntimeException("Return value type is not porperly initialized to be loaded.");
        }
        mv.visitVarInsn(returnType.getOpcode(Opcodes.ILOAD), returnVar);
    }
}