Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/src/net/sf/jode/expr/Operator.java

329 lines
10 KiB

/* Operator Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program 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 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.expr;
import net.sf.jode.type.Type;
import net.sf.jode.decompiler.TabbedPrintWriter;
///#def COLLECTIONS java.util
import java.util.Collection;
import java.util.Set;
///#enddef
public abstract class Operator extends Expression {
/* Don't reorder these constants unless you know what you are doing! */
public final static int ADD_OP = 1;
public final static int SUB_OP = 2;
public final static int SHIFT_OP = 6;
public final static int AND_OP = 9;
public final static int ASSIGN_OP = 12;
public final static int OPASSIGN_OP= 12;
public final static int INC_OP = 24; /* must be even! */
public final static int DEC_OP = 25;
public final static int COMPARE_OP = 26; /* must be even! */
public final static int EQUALS_OP = 26;
public final static int NOTEQUALS_OP = 27;
public final static int LESS_OP = 28;
public final static int GREATEREQ_OP = 29;
public final static int GREATER_OP = 30;
public final static int LESSEQ_OP = 31;
public final static int LOG_AND_OP = 32; /* must be even! */
public final static int LOG_OR_OP = 33;
public final static int LOG_NOT_OP = 34;
public final static int NEG_OP = 36;
static String opString[] = {
"", " + ", " - ", " * ", " / ", " % ",
" << ", " >> ", " >>> ", " & ", " | ", " ^ ",
" = ", " += ", " -= ", " *= ", " /= ", " %= ",
" <<= ", " >>= ", " >>>= ", " &= ", " |= ", " ^= ",
"++", "--",
" == "," != "," < "," >= "," > ", " <= ", " && ", " || ",
"!", "~", "-"
};
protected int operatorIndex;
private int operandcount;
Expression[] subExpressions;
public Operator(Type type) {
this(type,0);
}
public Operator(Type type, int op) {
super(type);
this.operatorIndex = op;
if (type == null)
throw new InternalError("type == null");
}
public void initOperands(int opcount) {
operandcount = opcount;
subExpressions = new Expression[opcount];
for (int i=0; i < opcount; i++) {
subExpressions[i] = new NopOperator(Type.tUnknown);
subExpressions[i].parent = this;
}
updateSubTypes();
}
public int getFreeOperandCount() {
return operandcount;
}
/**
* Tells if this is an operator, that doesn't have any
* subExpression, yet.
*/
public boolean isFreeOperator() {
return subExpressions.length == 0
|| subExpressions[subExpressions.length-1] instanceof NopOperator;
}
/**
* Tells if this is an operator, that doesn't have any
* subExpression, yet, and that expects opcount operands
*/
public boolean isFreeOperator(int opcount) {
return subExpressions.length == opcount
&& (opcount == 0
|| subExpressions[opcount-1] instanceof NopOperator);
}
public Expression addOperand(Expression op) {
for (int i= subExpressions.length; i-- > 0;) {
int opcount = subExpressions[i].getFreeOperandCount();
if (opcount > 0) {
subExpressions[i] = subExpressions[i].addOperand(op);
operandcount
+= subExpressions[i].getFreeOperandCount() - opcount;
updateType();
return this;
}
}
throw new InternalError("addOperand called, but no operand needed");
}
public Operator getOperator() {
return this;
}
public Expression[] getSubExpressions() {
return subExpressions;
}
public void setSubExpressions(int i, Expression expr) {
int diff = expr.getFreeOperandCount()
- subExpressions[i].getFreeOperandCount();
subExpressions[i] = expr;
expr.parent = this;
for (Operator ce = this; ce != null; ce = (Operator) ce.parent)
ce.operandcount += diff;
updateType();
}
public int getOperatorIndex() {
return operatorIndex;
}
public void setOperatorIndex(int op) {
operatorIndex = op;
}
public String getOperatorString() {
return opString[operatorIndex];
}
public boolean opEquals(Operator o) {
return this == o;
}
public Expression simplify() {
for (int i=0; i< subExpressions.length; i++) {
subExpressions[i] = subExpressions[i].simplify();
subExpressions[i].parent = this;
}
return this;
}
public void fillInGenSet(Collection in, Collection gen) {
for (int i=0; i< subExpressions.length; i++)
subExpressions[i].fillInGenSet(in,gen);
}
public void fillDeclarables(Collection used) {
for (int i=0; i< subExpressions.length; i++)
subExpressions[i].fillDeclarables(used);
}
public void makeDeclaration(Set done) {
for (int i=0; i< subExpressions.length; i++)
subExpressions[i].makeDeclaration(done);
}
/**
* Checks if the value of the given expression can change, due to
* side effects in this expression. If this returns false, the
* expression can safely be moved behind the current expresion.
* @param expr the expression that should not change.
*/
public boolean hasSideEffects(Expression expr) {
if (expr instanceof MatchableOperator
&& expr.containsConflictingLoad((MatchableOperator)expr))
return true;
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].hasSideEffects(expr))
return true;
}
return false;
}
/**
* Checks if this expression contains a conflicting load, that
* matches the given CombineableOperator. The sub expressions are
* not checked.
* @param op The combineable operator.
* @return if this expression contains a matching load.
*/
public boolean containsConflictingLoad(MatchableOperator op) {
if (op.matches(this))
return true;
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].containsConflictingLoad(op))
return true;
}
return false;
}
/**
* Checks if this expression contains a matching load, that matches the
* given Expression.
* @param comb The store expression.
* @return true, iff this expression contains a matching load.
* @exception ClassCastException, if e.getOperator
* is not a CombineableOperator.
*/
public boolean containsMatchingLoad(CombineableOperator comb) {
if (comb.getLValue().matches(this)) {
if (subsEquals((Operator) comb.getLValue()))
return true;
}
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].containsMatchingLoad(comb))
return true;
}
return false;
}
/**
* Checks if the given Expression (which must be a CombineableOperator)
* can be combined into this expression.
* @param e The store expression, must be of type void.
* @return 1, if it can, 0, if no match was found and -1, if a
* conflict was found. You may wish to check for >0.
* @exception ClassCastException, if e.getOperator
* is not a CombineableOperator.
*/
public int canCombine(CombineableOperator combOp) {
// GlobalOptions.err.println("Try to combine "+e+" into "+this);
if (combOp.getLValue() instanceof LocalStoreOperator
&& ((Operator)combOp).getFreeOperandCount() == 0) {
// Special case for locals created on inlining methods, which may
// combine everywhere, as long as there are no side effects.
for (int i=0; i < subExpressions.length; i++) {
int result = subExpressions[i].canCombine(combOp);
if (result != 0)
return result;
if (subExpressions[i].hasSideEffects((Expression)combOp))
return -1;
}
}
if (combOp.lvalueMatches(this))
return subsEquals((Operator)combOp) ? 1 : -1;
if (subExpressions.length > 0)
return subExpressions[0].canCombine(combOp);
return 0;
}
/**
* Combines the given Expression (which should be a StoreInstruction)
* into this expression. You must only call this if
* canCombine returns the value 1.
* @param e The store expression.
* @return The combined expression.
* @exception ClassCastException, if e.getOperator
* is not a CombineableOperator.
*/
public Expression combine(CombineableOperator comb) {
Operator combOp = (Operator) comb;
if (comb.lvalueMatches(this)) {
/* We already checked in canCombine that subExpressions match */
comb.makeNonVoid();
combOp.parent = parent;
return combOp;
}
for (int i=0; i < subExpressions.length; i++) {
Expression combined = subExpressions[i].combine(comb);
if (combined != null) {
subExpressions[i] = combined;
updateType();
return this;
}
}
return null;
}
public boolean subsEquals(Operator other) {
if (this == other)
return true;
if (other.subExpressions == null)
return (subExpressions == null);
if (subExpressions.length != other.subExpressions.length)
return false;
for (int i=0; i<subExpressions.length; i++) {
if(!subExpressions[i].equals(other.subExpressions[i]))
return false;
}
return true;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Operator))
return false;
Operator other = (Operator) o;
return opEquals(other) && subsEquals(other);
}
public boolean isConstant() {
for (int i=0; i< subExpressions.length; i++)
if (!subExpressions[i].isConstant())
return false;
return true;
}
public abstract void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException;
}