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.
216 lines
7.5 KiB
216 lines
7.5 KiB
/* CreateAssignExpression 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.flow;
|
|
import net.sf.jode.expr.*;
|
|
import net.sf.jode.type.Type;
|
|
|
|
public class CreateAssignExpression {
|
|
|
|
public static boolean transform(InstructionContainer ic,
|
|
StructuredBlock last) {
|
|
if (!(last.outer instanceof SequentialBlock)
|
|
|| !(ic.getInstruction() instanceof StoreInstruction)
|
|
|| !(ic.getInstruction().isVoid()))
|
|
return false;
|
|
|
|
return (createAssignOp(ic, last) || createAssignExpression(ic, last));
|
|
}
|
|
|
|
public static boolean createAssignOp(InstructionContainer ic,
|
|
StructuredBlock last) {
|
|
|
|
/* Situation:
|
|
*
|
|
* (push loadstoreOps) <- not checked
|
|
* sequBlock:
|
|
* dup (may be missing for static / local variables)
|
|
* opBlock:
|
|
* PUSH (optional narrow)((optional wide) load(stack) * RHS)
|
|
* (optional dup_x)
|
|
* store(POP)
|
|
*
|
|
* We transform it to:
|
|
* (push loadstoreOps)
|
|
* rightHandSide
|
|
* (optional dup_x)
|
|
* store(stack) *= (stack)
|
|
*
|
|
* If the optional dup is present the store*= becomes non void. */
|
|
|
|
SequentialBlock opBlock = (SequentialBlock) last.outer;
|
|
StoreInstruction store = (StoreInstruction) ic.getInstruction();
|
|
if (!store.isFreeOperator() || store.isOpAssign())
|
|
return false;
|
|
Expression lvalue = store.getSubExpressions()[0];
|
|
int lvalueCount = lvalue.getFreeOperandCount();
|
|
|
|
boolean isAssignOp = false;
|
|
if (opBlock.subBlocks[0] instanceof SpecialBlock) {
|
|
SpecialBlock dup = (SpecialBlock) opBlock.subBlocks[0];
|
|
if (dup.type != SpecialBlock.DUP
|
|
|| dup.depth != lvalueCount
|
|
|| dup.count != lvalue.getType().stackSize()
|
|
|| !(opBlock.outer instanceof SequentialBlock))
|
|
return false;
|
|
opBlock = (SequentialBlock) opBlock.outer;
|
|
isAssignOp = true;
|
|
}
|
|
|
|
if (!(opBlock.subBlocks[0] instanceof InstructionBlock))
|
|
return false;
|
|
|
|
InstructionBlock ib = (InstructionBlock) opBlock.subBlocks[0];
|
|
if (!(ib.getInstruction() instanceof Operator))
|
|
return false;
|
|
Operator expr = (Operator) ib.getInstruction();
|
|
if (expr.getFreeOperandCount() != lvalueCount)
|
|
return false;
|
|
Type rvalueType = expr.getType();
|
|
|
|
SpecialBlock dup = null;
|
|
|
|
if (lvalueCount > 0) {
|
|
if (!(opBlock.outer instanceof SequentialBlock)
|
|
|| !(opBlock.outer.getSubBlocks()[0] instanceof SpecialBlock))
|
|
return false;
|
|
|
|
SequentialBlock sequBlock = (SequentialBlock) opBlock.outer;
|
|
dup = (SpecialBlock) sequBlock.subBlocks[0];
|
|
|
|
if (dup.type != SpecialBlock.DUP
|
|
|| dup.depth != 0 || dup.count != lvalueCount)
|
|
return false;
|
|
}
|
|
int opIndex;
|
|
Expression rightHandSide;
|
|
|
|
if (expr instanceof ConvertOperator
|
|
&& expr.getSubExpressions()[0] instanceof Operator
|
|
&& expr.getType().isOfType(lvalue.getType())) {
|
|
|
|
/* This gets tricky. We need to allow something like
|
|
* s = (short) (int) ((double) s / 0.1);
|
|
*/
|
|
expr = (Operator) expr.getSubExpressions()[0];
|
|
while (expr instanceof ConvertOperator
|
|
&& expr.getSubExpressions()[0] instanceof Operator)
|
|
expr = (Operator) expr.getSubExpressions()[0];
|
|
}
|
|
if (expr instanceof BinaryOperator) {
|
|
opIndex = expr.getOperatorIndex();
|
|
if (opIndex < Operator.ADD_OP || opIndex >= Operator.ASSIGN_OP)
|
|
return false;
|
|
|
|
if (!(expr.getSubExpressions()[0] instanceof Operator))
|
|
return false;
|
|
|
|
Operator loadExpr = (Operator) expr.getSubExpressions()[0];
|
|
while (loadExpr instanceof ConvertOperator
|
|
&& loadExpr.getSubExpressions()[0] instanceof Operator)
|
|
loadExpr = (Operator) loadExpr.getSubExpressions()[0];
|
|
|
|
if (!store.lvalueMatches(loadExpr)
|
|
|| !(loadExpr.isFreeOperator(lvalueCount)))
|
|
return false;
|
|
|
|
if (lvalue instanceof LocalStoreOperator)
|
|
((LocalLoadOperator)loadExpr).getLocalInfo().combineWith
|
|
(((LocalStoreOperator)lvalue).getLocalInfo());
|
|
|
|
rightHandSide = expr.getSubExpressions()[1];
|
|
} else {
|
|
/* For String += the situation is more complex.
|
|
* what is marked as load(stack) * rightHandSide above is
|
|
* really (after simplification):
|
|
*
|
|
* PUSH ((load(stack) + right) + Hand) + Side
|
|
*/
|
|
Expression simple = expr.simplifyString();
|
|
rightHandSide = simple;
|
|
/* Now search for the leftmost operand ... */
|
|
Operator lastExpr = null;
|
|
Operator parent = null;
|
|
while (simple instanceof StringAddOperator) {
|
|
parent = lastExpr;
|
|
lastExpr = (Operator) simple;
|
|
simple = lastExpr.getSubExpressions()[0];
|
|
}
|
|
|
|
/* ... check it ... */
|
|
if (lastExpr == null
|
|
|| !(simple instanceof Operator)
|
|
|| !store.lvalueMatches((Operator) simple)
|
|
|| !(((Operator) simple).isFreeOperator(lvalueCount)))
|
|
return false;
|
|
|
|
if (lvalue instanceof LocalStoreOperator)
|
|
((LocalLoadOperator)simple).getLocalInfo().combineWith
|
|
(((LocalStoreOperator)lvalue).getLocalInfo());
|
|
|
|
/* ... and remove it. */
|
|
if (parent != null) {
|
|
parent.setSubExpressions(0, lastExpr.getSubExpressions()[1]);
|
|
} else {
|
|
rightHandSide = lastExpr.getSubExpressions()[1];
|
|
}
|
|
|
|
opIndex = Operator.ADD_OP;
|
|
}
|
|
|
|
if (dup != null)
|
|
dup.removeBlock();
|
|
ib.setInstruction(rightHandSide);
|
|
|
|
lvalue.setType(rvalueType);
|
|
store.makeOpAssign(Operator.OPASSIGN_OP + opIndex);
|
|
|
|
if (isAssignOp)
|
|
store.makeNonVoid();
|
|
last.replace(opBlock.subBlocks[1]);
|
|
return true;
|
|
}
|
|
|
|
public static boolean createAssignExpression(InstructionContainer ic,
|
|
StructuredBlock last) {
|
|
/* Situation:
|
|
* sequBlock:
|
|
* dup_X(lvalue_count)
|
|
* store(POP) = POP
|
|
*/
|
|
SequentialBlock sequBlock = (SequentialBlock) last.outer;
|
|
StoreInstruction store = (StoreInstruction) ic.getInstruction();
|
|
|
|
if (sequBlock.subBlocks[0] instanceof SpecialBlock
|
|
&& store.isFreeOperator()) {
|
|
|
|
Expression lvalue = store.getSubExpressions()[0];
|
|
SpecialBlock dup = (SpecialBlock) sequBlock.subBlocks[0];
|
|
if (dup.type != SpecialBlock.DUP
|
|
|| dup.depth != lvalue.getFreeOperandCount()
|
|
|| dup.count != lvalue.getType().stackSize())
|
|
return false;
|
|
|
|
dup.removeBlock();
|
|
store.makeNonVoid();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|