/*
* RTLSpecialExpression.java - This file is part of the Jakstab project.
* Copyright 2007-2015 Johannes Kinder <jk@jakstab.org>
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, see <http://www.gnu.org/licenses/>.
*/
package org.jakstab.rtl.expressions;
import java.util.Arrays;
import java.util.Set;
import org.jakstab.rtl.*;
import org.jakstab.ssl.Architecture;
import org.jakstab.util.FastSet;
import org.jakstab.util.Logger;
/**
* "Special" expressions which are not (yet) supported in RTLOperation.
*
* @author Johannes Kinder
*/
public class RTLSpecialExpression extends AbstractRTLExpression implements RTLExpression {
public static final String FTRUNC = "ftrunc";
public static final String LOG2 = "log2";
public static final String TICKCOUNT = "tickcount";
public static final String GETPROCADDRESS = "getProcAddress";
public static final String DBG_PRINTF = "dbgPrintf";
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(RTLSpecialExpression.class);
protected Set<RTLMemoryLocation> usedMemoryLocations = null;
private final String operation;
private final RTLExpression[] operands;
private final int operandCount;
private final int size;
private final int bitWidth;
protected RTLSpecialExpression(String operation, RTLExpression... operands) {
super();
this.operation = operation;
if (operation.equals(TICKCOUNT)) bitWidth = 64;
else if (operation.equals(GETPROCADDRESS)) bitWidth = 32;
else if (operation.equals(DBG_PRINTF)) bitWidth = 32;
else {
// Everything else is floating point stuff anyway
bitWidth = 80;
//logger.warn("Unsupported special expression: " + operation);
}
if (operands == null || operands.length == 0 || operands[0] == null ) {
this.operandCount = 0;
this.operands = null;
this.size = 1;
} else {
this.operands = operands;
int opCount = operands.length;
int theSize = 1;
// See if it's actually less real operands
for (int i=0; i < operands.length; i++)
if (operands[i] == null) {
opCount = i;
break;
} else theSize += operands[i].size();
this.operandCount = opCount;
this.size = theSize;
}
}
/**
* @return the operation
*/
public String getOperator() {
return operation;
}
/**
* @return the operands
*/
public RTLExpression[] getOperands() {
return operands;
}
public int getOperandCount() {
return operandCount;
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) return false;
RTLSpecialExpression other = (RTLSpecialExpression)obj;
return other.operation.equals(this.operation) && Arrays.equals(this.operands, other.operands);
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return 7 + operation.hashCode() + Arrays.hashCode(operands);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if (operandCount == 0) return operation.toString();
StringBuilder res = new StringBuilder();
res.append(operation.toString() + "(");
res.append(operands[0].toString());
for (int i = 1; i < operandCount; i++)
res.append(", " + operands[i].toString());
res.append(')');
return res.toString();
}
@Override
public RTLExpression evaluate(Context context) {
RTLExpression[] evaledOperands = new RTLExpression[operandCount];
for(int i=0; i<operandCount; i++)
evaledOperands[i] = operands[i].evaluate(context);
return ExpressionFactory.createSpecialExpression(operation, evaledOperands);
}
@Override
public SetOfVariables getUsedVariables() {
if (usedVariables == null) {
usedVariables = new SetOfVariables();
for(int i=0; i<operandCount; i++) {
usedVariables.addAll(operands[i].getUsedVariables());
}
}
return usedVariables;
}
@Override
public Set<RTLMemoryLocation> getUsedMemoryLocations() {
if (usedMemoryLocations == null) {
usedMemoryLocations = new FastSet<RTLMemoryLocation>();
for(int i=0; i<operandCount; i++) {
usedMemoryLocations.addAll(operands[i].getUsedMemoryLocations());
}
}
return usedMemoryLocations;
}
@Override
public int size() {
return size;
}
@Override
public int getBitWidth() {
return bitWidth;
}
@Override
public RTLExpression inferBitWidth(Architecture arch, int expectedBitWidth)
throws TypeInferenceException {
// TODO: implement this
return this;
}
@Override
public <T> T accept(ExpressionVisitor<T> visitor) {
return visitor.visit(this);
}
}