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

org.evosuite.symbolic.instrument.OperandStack Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.symbolic.instrument;

import static org.evosuite.dse.util.Assertions.check;
import static org.evosuite.symbolic.instrument.ConcolicConfig.VM_FQ;
import static org.objectweb.asm.Opcodes.BIPUSH;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.DUP2;
import static org.objectweb.asm.Opcodes.DUP2_X1;
import static org.objectweb.asm.Opcodes.DUP2_X2;
import static org.objectweb.asm.Opcodes.DUP_X1;
import static org.objectweb.asm.Opcodes.DUP_X2;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.ICONST_2;
import static org.objectweb.asm.Opcodes.ICONST_3;
import static org.objectweb.asm.Opcodes.ICONST_4;
import static org.objectweb.asm.Opcodes.ICONST_5;
import static org.objectweb.asm.Opcodes.ICONST_M1;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.POP;
import static org.objectweb.asm.Opcodes.POP2;
import static org.objectweb.asm.Opcodes.SIPUSH;
import static org.objectweb.asm.Opcodes.SWAP;
import static org.objectweb.asm.Type.INT_TYPE;
import static org.objectweb.asm.Type.VOID_TYPE;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

/*
    This class is taken and adapted from the DSC tool developed by Christoph Csallner.
    Link at :
    http://ranger.uta.edu/~csallner/dsc/index.html
 */

/**
 * Helper class
 * 
 * Methods to generate bytecodes that mutate the
 * operand stack
 * 
 * TODO: Handle all cases via local variables, via LocalVariablesSorter:
 * http://asm.ow2.org/asm30/javadoc/user/org/objectweb/asm/commons/LocalVariablesSorter.html
 * 
 * @author [email protected] (Christoph Csallner)
 */
final class OperandStack {

	private final MethodVisitor mv;
	private static final String CALLER_STACK_PARAM = "CALLER_STACK_PARAM"; //$NON-NLS-1$
	private static final Type 	TYPE_OBJECT = Type.getObjectType("java/lang/Object"); //$NON-NLS-1$
	
	OperandStack(MethodVisitor mv) {
		this.mv = mv;	
	}

	private String desc(Type returnType, Type... argumentTypes) {
		StringBuffer desc = new StringBuffer();
		desc.append("("); //$NON-NLS-1$
		for (Type type: argumentTypes)
			desc.append(type.getDescriptor());
		desc.append(")"); //$NON-NLS-1$
		desc.append(returnType.getDescriptor());
		return desc.toString();
	}

	/**
	 * Push i onto our operand stack
	 */
	void pushInt(int i) {
		switch (i) {
		case -1: 
			mv.visitInsn(ICONST_M1);
			return;
		case 0: 
			mv.visitInsn(ICONST_0);
			return;
		case 1: 
			mv.visitInsn(ICONST_1);
			return;
		case 2: 
			mv.visitInsn(ICONST_2);
			return;
		case 3: 
			mv.visitInsn(ICONST_3);
			return;
		case 4: 
			mv.visitInsn(ICONST_4);
			return;
		case 5: 
			mv.visitInsn(ICONST_5);
			return;
		}
		if (i>=Byte.MIN_VALUE && i<=Byte.MAX_VALUE) {
			mv.visitIntInsn(BIPUSH, i);
			return;
		}
		if (i>=Short.MIN_VALUE && i<=Short.MAX_VALUE) {
			mv.visitIntInsn(SIPUSH, i);
			return;
		}
		mv.visitLdcInsn(Integer.valueOf(i));
	}
	
	
	/**
	 * ...
	 * ==>
	 * ..., a, b, c
	 */
	void pushStrings(String a, String b, String c) {
		mv.visitLdcInsn(a);
		mv.visitLdcInsn(b);
		mv.visitLdcInsn(c);
	}

	/** 
	 * ..., b1, a1
	 * ==>
	 * ..., b1, a1, b1
	 */
	void b1a1__b1a1b1() {
		/* ..., b1, a1*/
		mv.visitInsn(SWAP);
		/* ..., a1, b1*/
		mv.visitInsn(DUP_X1);
		/* ..., b1, a1, b1*/
	}

	/**
	 * ..., b1, a2 
	 * ==> 
	 * ..., b1, a2, b1
	 */
	void b1a2__b1a2b1() {
		/* ..., b1, a2 */
		mv.visitInsn(DUP2_X1);
		/* ..., a2, b1, a2 */
		mv.visitInsn(POP2);
		/* ..., a2, b1 */
		mv.visitInsn(DUP_X2);
		/* ..., b1, a2, b1 */
	}

	/** 
	 * ..., b2, a1
	 * ==>
	 * ..., b2, a1, b2
	 */
	void b2a1__b2a1b2() {
		/* ..., b2, a1 */
		mv.visitInsn(DUP_X2);
		/* ..., a1, b2, a1 */
		mv.visitInsn(POP);
		/* ..., a1, b2 */
		mv.visitInsn(DUP2_X1);
		/* ..., b2, a1, b2 */
	}

	/** 
	 * ..., b2, a2
	 * ==>
	 * ..., b2, a2, b2
	 */
	void b2a2__b2a2b2() {
		/* ..., b2, a2 */
		mv.visitInsn(DUP2_X2);
		/* ..., a2, b2, a2 */
		mv.visitInsn(POP2);
		/* ..., a2, b2 */
		mv.visitInsn(DUP2_X2);
		/* ..., b2, a2, b2 */
	}

	/**
	 * Transform top of operand stack, assuming each operand is of category-1:
	 * 
	 * ..., c1, b1, a1
	 * ==>
	 * ..., c1, b1, a1, c1
	 */
	void c1b1a1__c1b1a1c1() {
		/* ..., 2, 1, 0*/
		mv.visitInsn(DUP_X2);
		/* ..., 0, 2, 1, 0*/
		mv.visitInsn(POP);
		/* ..., 0, 2, 1 */
		mv.visitInsn(DUP_X2);
		/* ..., 1, 0, 2, 1 */
		mv.visitInsn(POP);
		/* ..., 1, 0, 2 */
		mv.visitInsn(DUP_X2);
		/* ..., 2, 1, 0, 2 */
	}

	/**
	 * ..., c1, b1, a2
	 * ==>
	 * ..., c1, b1, a2, c1
	 */
	void c1b1a2__c1b1a2c1() {
		/* ..., c1, b1, a2 */
		mv.visitInsn(DUP2_X2);
		/* ..., a2, c1, b1, a2 */
		mv.visitInsn(POP2);
		/* ..., a2, c1, b1 */
		mv.visitInsn(DUP2_X2);
		/* ..., c1, b1, a2, c1, b1 */
		mv.visitInsn(POP);
		/* ..., c1, b1, a2, c1 */
	}

	/**
	 * ..., c1, b2, a1
	 * ==>
	 * ..., c1, b2, a1, c1
	 */
	void c1b2a1__c1b2a1c1() {
		/* ..., c1, b2, a1 */
		mv.visitInsn(DUP_X2);						// Form 2
		/* ..., c1, a1, b2, a1 */
		mv.visitInsn(POP);
		/* ..., c1, a1, b2 */
		mv.visitInsn(DUP2_X2);					// Form 2
		/* ..., b2, c1, a1, b2 */
		mv.visitInsn(POP2);
		/* ..., b2, c1, a1 */
		mv.visitInsn(DUP2_X2);					// Form 3
		/* ..., c1, a1, b2, c1, a1 */
		mv.visitInsn(POP);
		/* ..., c1, a1, b2, c1 */
		mv.visitInsn(DUP_X2);						// Form 2
		/* ..., c1, a1, c1, b2, c1 */
		mv.visitInsn(POP);
		/* ..., c1, a1, c1, b2 */
		mv.visitInsn(DUP2_X2);					// Form 2
		/* ..., c1, b2, a1, c1, b2 */
		mv.visitInsn(POP2);
		/* ..., c1, b2, a1, c1 */
	}

	/**
	 * Pass a single parameter
	 */
	void passCallerStackParam(Type argType, int paramNr, int calleeLocalsIndex) {
		/* Replace concrete complex type by java.lang.Object */
		Type type = argType;
		if (type.getSort()==Type.OBJECT || type.getSort()==Type.ARRAY)
			type = TYPE_OBJECT;
	
		pushInt(paramNr);
		pushInt(calleeLocalsIndex);
		String signature = desc(VOID_TYPE, type, INT_TYPE, INT_TYPE);
		mv.visitMethodInsn(INVOKESTATIC, VM_FQ, CALLER_STACK_PARAM, signature);
	}

	/**
	 * Pass non-receiver-parameters one at a time, 
	 * right to left, downwards the operand stack
	 */
	void passCallerStackParams(Type[] argTypes, boolean needThis) {
		if (argTypes==null || argTypes.length==0)
			return;
		
		int calleeLocalsIndex = 0;
		for (Type type: argTypes)
			calleeLocalsIndex += type.getSize();
		if (needThis)
			calleeLocalsIndex += 1;
		
		int paramNr = argTypes.length - 1;	// work right to left
		
		
		
		
		if (argTypes[paramNr].getSize()==1) {
			calleeLocalsIndex -= 1;
			mv.visitInsn(DUP);
			passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			if (argTypes.length==1)
				return;
			paramNr -= 1;
			
			if (argTypes[paramNr].getSize()==1) {
				calleeLocalsIndex -= 1;
				b1a1__b1a1b1();
				passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			}
			else if (argTypes[paramNr].getSize()==2) {
				calleeLocalsIndex -= 2;
				b2a1__b2a1b2();
				passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			}
			else
				check(false);  		
		}
		else if (argTypes[paramNr].getSize()==2) {
			calleeLocalsIndex -= 2;
			mv.visitInsn(DUP2);
			passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			if (argTypes.length==1)
				return;
			paramNr -= 1;
			if (argTypes[paramNr].getSize()==1) {
				calleeLocalsIndex -= 1;
				b1a2__b1a2b1();
				passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			}
			else if (argTypes[paramNr].getSize()==2) {
				calleeLocalsIndex -= 2;
				b2a2__b2a2b2();
				passCallerStackParam(argTypes[paramNr], paramNr, calleeLocalsIndex);
			}
			else
				check(false);
		}
		else
			check(false);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy