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

com.dragome.compiler.parser.Pass1 Maven / Gradle / Ivy

There is a newer version: 0.96-beta4
Show newest version
/*******************************************************************************
 * Copyright (c) 2011-2014 Fernando Petrola
 * 
 * This file is part of Dragome SDK.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 ******************************************************************************/

// Copyright 2011 The j2js Authors. All Rights Reserved.
//
// This file is part of j2js.
//
// j2js is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// j2js 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 General Public License
// along with j2js. If not, see .

package com.dragome.compiler.parser;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.CodeException;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantCP;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantDouble;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantFloat;
import org.apache.bcel.classfile.ConstantInteger;
import org.apache.bcel.classfile.ConstantLong;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantString;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Utility;
import org.apache.bcel.generic.BasicType;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InstructionTargeter;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import org.apache.bcel.util.ByteSequence;

import com.dragome.compiler.DragomeJsCompiler;
import com.dragome.compiler.Project;
import com.dragome.compiler.ast.ASTNode;
import com.dragome.compiler.ast.ASTNodeStack;
import com.dragome.compiler.ast.ArrayAccess;
import com.dragome.compiler.ast.ArrayCreation;
import com.dragome.compiler.ast.ArrayInitializer;
import com.dragome.compiler.ast.Assignment;
import com.dragome.compiler.ast.Block;
import com.dragome.compiler.ast.BooleanExpression;
import com.dragome.compiler.ast.CastExpression;
import com.dragome.compiler.ast.CatchClause;
import com.dragome.compiler.ast.ClassInstanceCreation;
import com.dragome.compiler.ast.ClassLiteral;
import com.dragome.compiler.ast.ConditionalBranch;
import com.dragome.compiler.ast.ExceptionHandler;
import com.dragome.compiler.ast.ExceptionHandlers;
import com.dragome.compiler.ast.Expression;
import com.dragome.compiler.ast.FieldAccess;
import com.dragome.compiler.ast.FieldRead;
import com.dragome.compiler.ast.FieldWrite;
import com.dragome.compiler.ast.InfixExpression;
import com.dragome.compiler.ast.InstanceofExpression;
import com.dragome.compiler.ast.Jump;
import com.dragome.compiler.ast.JumpSubRoutine;
import com.dragome.compiler.ast.MethodBinding;
import com.dragome.compiler.ast.MethodDeclaration;
import com.dragome.compiler.ast.MethodInvocation;
import com.dragome.compiler.ast.NoOperation;
import com.dragome.compiler.ast.NullLiteral;
import com.dragome.compiler.ast.NumberLiteral;
import com.dragome.compiler.ast.PrefixExpression;
import com.dragome.compiler.ast.PrimitiveCast;
import com.dragome.compiler.ast.ReturnStatement;
import com.dragome.compiler.ast.StringLiteral;
import com.dragome.compiler.ast.SynchronizedBlock;
import com.dragome.compiler.ast.ThisExpression;
import com.dragome.compiler.ast.ThrowStatement;
import com.dragome.compiler.ast.TryStatement;
import com.dragome.compiler.ast.VariableBinding;
import com.dragome.compiler.ast.VariableDeclaration;
import com.dragome.compiler.exceptions.UnhandledCompilerProblemException;
import com.dragome.compiler.graph.ControlFlowGraph;
import com.dragome.compiler.graph.Node;
import com.dragome.compiler.graph.SwitchEdge;
import com.dragome.compiler.graph.TryHeaderNode;
import com.dragome.compiler.parser.Form.Value;
import com.dragome.compiler.type.Signature;
import com.dragome.compiler.units.ClassUnit;
import com.dragome.compiler.utils.Log;
import com.dragome.compiler.utils.Utils;

public class Pass1
{

	private ConstantPool constantPool;

	private ByteSequence bytes;

	private static ASTNode currentNode;

	private ASTNodeStack stack;

	private Code code;

	private MethodDeclaration methodDecl;

	private Method method;

	private List tryStatements= new ArrayList();

	private ControlFlowGraph graph= new ControlFlowGraph(tryStatements);

	private int depth;

	private static Log logger= Log.getLogger();

	private boolean wide= false;

	public static ASTNode getCurrentNode()
	{
		return currentNode;
	}

	public Pass1(JavaClass jc)
	{
		constantPool= jc.getConstantPool();
		loopFound= false;
	}

	private CatchClause createCatchClause(TryStatement tryStmt, ExceptionHandler handle)
	{
		CatchClause cStmt= new CatchClause(handle.getHandlerPC());
		VariableDeclaration decl= new VariableDeclaration(VariableDeclaration.LOCAL_PARAMETER);
		decl.setName("_EX_");
		decl.setType(handle.getCatchType(constantPool));
		cStmt.setException(decl);
		tryStmt.addCatchStatement(cStmt);
		return cStmt;
	}

	private void makeTryFrames()
	{
		for (int i= 0; i < tryStatements.size(); i++)
		{
			TryStatement tryStmt= tryStatements.get(i);
			makeTryFrame(tryStmt);
		}
	}

	private void makeTryFrame(TryStatement stmt)
	{
		TryHeaderNode header= stmt.header;

		Node tryNode= graph.getOrCreateNode(stmt.getBeginIndex());
		tryNode.stack= new ASTNodeStack();
		header.setTryBody(tryNode);

		CatchClause clause= (CatchClause) stmt.getCatchStatements().getFirstChild();
		while (clause != null)
		{
			// Push implicit exception.
			Node catchNode= graph.createNode(clause.getBeginIndex());
			// catchNode.type = NodeType.CATCH;
			catchNode.stack= new ASTNodeStack(new VariableBinding(clause.getException()));
			header.addCatchNode(catchNode);

			clause= (CatchClause) clause.getNextSibling();
		}
	}

	private void compileCodeException()
	{
		ExceptionHandlers handlers= new ExceptionHandlers(code);

		Iterator handleIterator= handlers.iterator();

		ExceptionHandler handle= handleIterator.hasNext() ? handleIterator.next() : null;
		while (handle != null)
		{
			boolean hasFinally= false;
			int start= handle.getStartPC();
			int end= handle.getEndPC();

			TryStatement tryStmt= new TryStatement();
			tryStmt.header= (TryHeaderNode) graph.createNode(TryHeaderNode.class);
			tryStmt.header.tryStmt= tryStmt;

			Block tryBlock= new Block(start, end);
			tryStmt.setTryBlock(tryBlock);

			// tryStmt.setBeginIndex(start);

			tryStatements.add(tryStmt);

			CatchClause cStmt= null;

			// Collect all non-default handlers. The range of each handler is
			// from the 'store'-instruction to the beginning of the next
			// handler.
			while (handle != null && !handle.isDefault() && handle.getStartPC() == start && handle.getEndPC() == end)
			{
				if (cStmt != null)
				{
					cStmt.setEndIndex(handle.getHandlerPC() - 1);
				}
				cStmt= createCatchClause(tryStmt, handle);
				handle= handleIterator.hasNext() ? handleIterator.next() : null;
			}

			int foo= -1;
			if (handle != null && handle.isDefault() && handle.getStartPC() == start)
			{
				// Collect first default handler.
				hasFinally= true;
				if (cStmt != null)
				{
					cStmt.setEndIndex(handle.getHandlerPC() - 1);
					tryStmt.setEndIndex(handle.getHandlerPC() - 1);
					// Warning: We only set a lower bound for the end index. The
					// correct index is set later
					// when the finally statement is analysed.
				}
				cStmt= createCatchClause(tryStmt, handle);
				foo= handle.getHandlerPC();
				handle= handleIterator.hasNext() ? handleIterator.next() : null;
			}

			// Last catch stmt has no endIndex, yet!

			while (handle != null && handle.isDefault() && (handle.getHandlerPC() == foo))
			{
				// Skip all remaining default handlers.
				throw new RuntimeException("remaining default handlers");
				// handle = handleIterator.hasNext()?handleIterator.next():null;
			}

			Block catches= tryStmt.getCatchStatements();
			if (catches.getChildCount() == 0)
			{
				throw new ParseException("A try clause must have at least one (possibly default) catch clause", tryStmt);
			}
			cStmt= (CatchClause) catches.getChildAt(0);
			tryBlock.setEndIndex(cStmt.getBeginIndex() - 1);
			cStmt= (CatchClause) catches.getLastChild();
			if (cStmt.getEndIndex() == Integer.MIN_VALUE)
			{
				cStmt.setEndIndex(cStmt.getBeginIndex() + 1);
			}
			tryStmt.setEndIndex(cStmt.getEndIndex());

			if (hasFinally)
			{
				// Can't say yet where finally block is located.
			}
		}
	}

	private void dumpCode()
	{
		InstructionList il= new InstructionList(code.getCode());
		InstructionHandle[] handles= il.getInstructionHandles();

		for (InstructionHandle handle : handles)
		{
			System.out.println(handle.toString(true));
			InstructionTargeter[] targeters= handle.getTargeters();
			if (targeters != null)
			{
				for (InstructionTargeter targeter : handle.getTargeters())
				{
					System.out.println("    Targeter: " + targeter.toString() + " " + targeter.getClass());
				}
			}
		}

		for (CodeException ce : code.getExceptionTable())
		{
			String exceptionType;
			if (ce.getCatchType() > 0)
			{
				Constant constant= constantPool.getConstant(ce.getCatchType());
				exceptionType= Pass1.constantToString(constant, constantPool);
			}
			else
			{
				exceptionType= "Default";
			}
			System.out.println(ce.toString() + " " + exceptionType);
		}
	}

	public void parse(Method theMethod, MethodDeclaration theMethodDecl) throws IOException
	{
		method= theMethod;
		methodDecl= theMethodDecl;

		code= method.getCode();

		if (logger.isDebugEnabled())
		{
			dumpCode();
		}

		Block.TAG= 0;

		compileCodeException();

		bytes= new ByteSequence(code.getCode());

		graph.createNode(0);

		makeTryFrames();

		parseStatement();

		try
		{
			Optimizer optimizer= new Optimizer(methodDecl, tempDecls);
			optimizer.optimize();
		}
		catch (Error e)
		{
			DragomeJsCompiler.errorCount++;
			if (logger.isDebugEnabled())
			{
				logger.debug("In Expression Optimizer:\n" + e + "\n" + Utils.stackTraceToString(e));
			}
			else
			{
				logger.error("In Expression Optimizer:\n " + e);
			}
		}

		Block block;
		if (DragomeJsCompiler.compiler.reductionLevel == 0)
		{
			block= graph.reduceDumb();
		}
		else
		{
			block= graph.reduce();
		}

		methodDecl.setBody(block);

		if (loopFound)
			throw new UnhandledCompilerProblemException();
	}

	private boolean isProcedure(ASTNode stmt)
	{
		if (stmt instanceof MethodInvocation)
		{
			MethodInvocation mi= (MethodInvocation) stmt;
			return mi.getTypeBinding().equals(Type.VOID);
		}
		return false;
	}

	Node cNode;

	Node lastCurrentNode;

	private boolean whileTryProblemDetected= false;

	private Jump lastJump;

	public static boolean loopFound= false;

	private void setCurrentNode(Node theNode)
	{
		if (cNode == theNode)
			return;
		cNode= theNode;
		if (cNode != null && cNode != lastCurrentNode)
		{
			logger.debug("Switched to " + cNode);
			lastCurrentNode= cNode;
		}
	}

	private void joinNodes(Node node)
	{
		Collection nodes= node.preds();
		Iterator iter= nodes.iterator();
		while (iter.hasNext())
		{
			Node n= (Node) iter.next();
			if (n.stack.size() == 0)
				iter.remove();
		}
		if (nodes.size() > 0)
		{
			mergeStacks(nodes, node.stack);
		}
	}

	private void selectActiveNode(int pc)
	{

		List activeNodes= new ArrayList();
		for (Node node : graph.getNodes())
		{
			if (node.getCurrentPc() == pc)
			{
				activeNodes.add(node);
			}
		}

		if (activeNodes.size() == 0)
		{

			Node node= graph.createNode(pc);
			setCurrentNode(node);
			return;
		}

		if (activeNodes.size() == 1)
		{

			Node node= activeNodes.get(0);
			setCurrentNode(node);
			return;
		}

		Node node= graph.getNode(pc);
		if (node == null)
			throw new RuntimeException("No node found at " + pc);

		setCurrentNode(node);

		activeNodes.remove(node);
		for (Node n : activeNodes)
		{
			graph.addEdge(n, node);
		}
	}

	private void expressionsToVariables(Node node, boolean clone)
	{
		if (node.stack.size() == 0)
			return;

		logger.debug("expressionsToVariables ...");

		for (int i= 0; i < node.stack.size(); i++)
		{
			Expression expr= (Expression) node.stack.get(i);

			if (expr instanceof VariableBinding && (((VariableBinding) expr).isTemporary()))
			{

				continue;
			}

			VariableBinding vb= methodDecl.createAnonymousVariableBinding(expr.getTypeBinding(), true);
			logger.debug("\t" + expr + ' ' + vb.getName());
			Assignment a= new Assignment(Assignment.Operator.ASSIGN);
			a.setLeftHandSide(vb);
			a.setRightHandSide(expr);

			node.block.appendChild(a);
			node.stack.set(i, clone ? (VariableBinding) vb.clone() : vb);
		}

		logger.debug("... expressionsToVariables");
	}

	private Object stacksIdentical(Collection sources, int index)
	{
		Expression expr= null;
		Iterator iter= sources.iterator();
		while (iter.hasNext())
		{
			Node node= (Node) iter.next();
			Expression e= (Expression) node.stack.get(index);
			if (expr == null)
			{
				expr= e;
			}
			else if (e != expr)
			{
				return expr.getTypeBinding();
			}
		}
		return expr;
	}

	private void mergeStacks(Collection sources, ASTNodeStack target)
	{
		logger.debug("Merging ...");

		Iterator iter= sources.iterator();
		while (iter.hasNext())
		{
			Node pred= (Node) iter.next();
			dump(pred.stack, "Stack for " + pred);
		}

		int stackSize= -1;

		iter= sources.iterator();
		while (iter.hasNext())
		{
			Node pred= (Node) iter.next();

			if (stackSize == -1)
			{
				stackSize= pred.stack.size();
			}
			else if (stackSize != pred.stack.size())
			{
				dump(sources);
				throw new RuntimeException("Stack size mismatch");
			}
		}

		for (int index= 0; index < stackSize; index++)
		{
			Object obj= stacksIdentical(sources, index);
			if (obj instanceof Expression)
			{
				target.add((Expression) ((Expression) obj).clone());
				logger.debug("\tIdentical: " + obj);
			}
			else
			{

				VariableBinding vb= methodDecl.createAnonymousVariableBinding((Type) obj, true);

				target.add(vb);

				iter= sources.iterator();
				while (iter.hasNext())
				{
					Node node= (Node) iter.next();
					Expression expr= (Expression) node.stack.get(index);

					Assignment a= new Assignment(Assignment.Operator.ASSIGN);
					a.setLeftHandSide((VariableBinding) vb.clone());
					if (expr instanceof VariableBinding)
						expr= (VariableBinding) expr.clone();
					a.setRightHandSide(expr);

					node.block.appendChild(a);
				}
				logger.debug("\t" + vb.getName());
			}
		}
		logger.debug("... Merging stacks");
	}

	public void parseStatement() throws IOException
	{
		depth= 0;

		while (bytes.available() > 0)
		{

			int pc= bytes.getIndex();

			if (cNode != null)
			{
				cNode.setCurrentPc(pc);
			}

			selectActiveNode(pc);

			if (cNode.getInitialPc() == pc)
			{
				joinNodes(cNode);
			}

			stack= cNode.stack;

			ASTNode stmt= parseInstruction();

			if (stmt instanceof NoOperation)
				continue;

			depth+= stmt.getStackDelta();

			if (stmt instanceof VariableBinding)
			{
				depth= depth;
			}

			logger.debug(" -> " + stmt + " @ " + methodDecl.getLineNumberCursor().getLineNumber(stmt) + ", depth:" + depth + ", delta:" + stmt.getStackDelta());

			if (stmt instanceof JumpSubRoutine)
			{
				JumpSubRoutine jsr= (JumpSubRoutine) stmt;
				cNode.block.setEndIndex(jsr.getEndIndex());

				Node finallyNode= graph.getNode(jsr.getTargetIndex());

				if (finallyNode == null)
				{

					finallyNode= graph.createNode(jsr.getTargetIndex());

					finallyNode.stack= new ASTNodeStack(new Expression());

				}
				finallyNode.jsrCallers.add(cNode);
				if (cNode.preds().size() == 1 && finallyNode.preds().size() == 0 && cNode.getPred() instanceof TryHeaderNode)
				{

					TryHeaderNode tryHeaderNode= (TryHeaderNode) cNode.getPred();

					tryHeaderNode.setFinallyNode(finallyNode);
				}

			}
			else if (stmt instanceof ConditionalBranch)
			{
				ConditionalBranch cond= (ConditionalBranch) stmt;

				if (bytes.getIndex() == cond.getTargetIndex())
				{

				}
				else
				{
					Node elseNode= graph.getOrCreateNode(bytes.getIndex());

					Node ifNode;
					if (cond.getTargetIndex() <= pc)
					{
						Node[] nodes= graph.getOrSplitNodeAt(cNode, cond.getTargetIndex());
						cNode= nodes[0];
						ifNode= nodes[1];
					}
					else
					{
						ifNode= graph.getOrCreateNode(cond.getTargetIndex());
					}

					BooleanExpression be= new BooleanExpression(cond.getExpression());

					graph.addIfElseEdge(cNode, ifNode, elseNode, be);
					expressionsToVariables(cNode, false);
					cNode= null;

					if (lastJump != null && tryStatements.size() > 0 && (cond.getBeginIndex() - 1 == lastJump.getEndIndex()))
						whileTryProblemDetected= true;

					for (TryStatement tryStatement : tryStatements)
					{
						boolean nextToTryBegining= tryStatement.getBeginIndex() - 1 == cond.getEndIndex();
						boolean sameThanTryBegining= tryStatement.getBeginIndex() == cond.getBeginIndex();
						//			sameThanTryBegining= false; //TODO identificar si es un while!
						if (nextToTryBegining || sameThanTryBegining)
							whileTryProblemDetected= true;
					}

					if (!whileTryProblemDetected)
						for (CodeException codeException : code.getExceptionTable())
						{
							boolean nextToTryBegining= codeException.getEndPC() == cond.getTargetIndex();
							if (nextToTryBegining)
								whileTryProblemDetected= true;
						}

					if (whileTryProblemDetected)
						throw new UnhandledCompilerProblemException();
				}
			}
			else if (stmt instanceof Jump)
			{
				int targetPc= ((Jump) stmt).getTargetIndex();
				lastJump= (Jump) stmt;
				Node targetNode;

				if (!whileTryProblemDetected)
					for (CodeException codeException : code.getExceptionTable())
					{
						boolean nextToTryBegining= codeException.getStartPC() - 1 == lastJump.getEndIndex();
						if (nextToTryBegining)
							throw new UnhandledCompilerProblemException();
					}

				if (targetPc <= pc)
				{
					if (whileTryProblemDetected)
						throw new UnhandledCompilerProblemException();

					loopFound= true;

					Node[] nodes= graph.getOrSplitNodeAt(cNode, targetPc);
					cNode= nodes[0];
					targetNode= nodes[1];
				}
				else
				{
					targetNode= graph.getOrCreateNode(targetPc);
				}
				graph.addEdge(cNode, targetNode);
				cNode= null;
			}
			else if (stmt instanceof SynchronizedBlock || isProcedure(stmt))
			{
				cNode.block.appendChild(stmt);
			}
			else if (stmt instanceof Assignment)
			{
				expressionsToVariables(cNode, true);
				cNode.block.appendChild(stmt);
			}
			else if (stmt instanceof ThrowStatement || stmt instanceof ReturnStatement)
			{
				cNode.block.appendChild(stmt);
				cNode.close();
				cNode= null;
			}
			else
			{
				stack.push(stmt);
			}
		}

	}

	void dump(Collection nodes)
	{
		if (!logger.isDebugEnabled())
			return;

		Iterator iter= nodes.iterator();
		while (iter.hasNext())
		{
			Node node= (Node) iter.next();
			dump(node.stack, node.toString());
		}
	}

	static void dump(List list, String msg)
	{
		if (!logger.isDebugEnabled())
			return;

		StringBuffer sb= new StringBuffer();
		sb.append("Begin dumping " + msg + "...\n");
		for (int i= 0; i < list.size(); i++)
		{
			ASTNode node= (ASTNode) list.get(i);
			sb.append("    " + i + ": " + node + "\n");
		}
		sb.append("... end of dump");

		logger.debug(sb.toString());
	}

	private VariableBinding createVariableBinding(int slot, Type type, boolean isWrite)
	{
		return methodDecl.createVariableBinding(VariableDeclaration.getLocalVariableName(method, slot, bytes.getIndex()), type, isWrite);
	}

	private InfixExpression createInfixRightLeft(InfixExpression.Operator op, Expression right, Expression left, Type type)
	{
		InfixExpression binOp= new InfixExpression(op);
		binOp.setTypeBinding(type);
		binOp.setOperands(left, right);
		return binOp;
	}

	private PrefixExpression createPrefix(PrefixExpression.Operator op, ASTNode operand, Type type)
	{
		PrefixExpression pe= new PrefixExpression();
		pe.setOperator(op);
		pe.setTypeBinding(type);
		pe.setOperand(operand);
		return pe;
	}

	private Form selectForm(InstructionType instructionType)
	{
		if (instructionType.getFormCount() == 1)
		{
			return instructionType.getForm(0);
		}
		FormLoop: for (int i= 0; i < instructionType.getFormCount(); i++)
		{
			Form form= instructionType.getForm(i);
			for (int j= 0; j < form.getIns().length; j++)
			{
				Form.Value in= form.getIns()[form.getIns().length - 1 - j];
				if (stack.peek(j).getCategory() != in.getCategory())
					continue FormLoop;
			}
			return form;
		}
		throw new RuntimeException("Could not determine correct form for " + instructionType);
	}

	private List tempDecls= new ArrayList();

	private Expression[] duplicate(Expression e)
	{
		if (e instanceof NumberLiteral || e instanceof ThisExpression || e instanceof StringLiteral)
		{

			return new Expression[] { e, (Expression) e.clone() };
		}

		if (e instanceof VariableBinding && ((VariableBinding) e).isTemporary())
		{
			VariableBinding vb1= (VariableBinding) e;
			VariableBinding vb2= (VariableBinding) vb1.clone();
			return new VariableBinding[] { vb1, vb2 };
		}

		Assignment a= new Assignment(Assignment.Operator.ASSIGN);
		a.setRange(bytes.getIndex(), bytes.getIndex());
		VariableBinding vb1= methodDecl.createAnonymousVariableBinding(e.getTypeBinding(), true);
		VariableBinding vb2= (VariableBinding) vb1.clone();
		VariableBinding vb3= (VariableBinding) vb1.clone();
		tempDecls.add(vb1.getVariableDeclaration());
		vb1.getVariableDeclaration().setParentNode(methodDecl);
		a.setLeftHandSide(vb1);
		a.setRightHandSide(e);
		cNode.block.appendChild(a);
		return new VariableBinding[] { vb2, vb3 };
	}

	private SwitchEdge getOrCreateCaseGroup(Node header, Map switchEdges, int startPc)
	{
		SwitchEdge switchEdge= switchEdges.get(startPc);
		if (switchEdge == null)
		{
			Node caseGroupNode= graph.createNode(startPc);
			switchEdge= (SwitchEdge) graph.addEdge(header, caseGroupNode, SwitchEdge.class);
			switchEdges.put(startPc, switchEdge);
		}

		return switchEdge;
	}

	private int readUnsigned() throws IOException
	{
		int index;
		if (wide)
		{
			index= bytes.readUnsignedShort();
			wide= false;
		}
		else
		{
			index= bytes.readUnsignedByte();
		}
		return index;
	}

	private int readSigned() throws IOException
	{
		int index;
		if (wide)
		{
			index= bytes.readShort();
			wide= false;
		}
		else
		{
			index= bytes.readByte();
		}
		return index;
	}

	private void dup1()
	{
		Expression[] value1= duplicate(stack.pop());
		stack.push(value1[0]);
		stack.push(value1[1]);
	}

	private void dup2()
	{
		Expression[] value1= duplicate(stack.pop());
		Expression[] value2= duplicate(stack.pop());
		stack.push(value2[0]);
		stack.push(value1[0]);
		stack.push(value2[1]);
		stack.push(value1[1]);
	}

	private ASTNode parseInstruction() throws IOException
	{
		int currentIndex= bytes.getIndex();
		short opcode= (short) bytes.readUnsignedByte();

		InstructionType instructionType= Const.instructionTypes[opcode];

		Form form= selectForm(instructionType);

		int opStackDelta= form.getOpStackDelta();

		ASTNode instruction= null;

		logger.debug(currentIndex + " " + instructionType.getName() + "[" + opcode + "] ");

		switch (opcode)
		{

			case Const.TABLESWITCH:

			case Const.LOOKUPSWITCH:
			{

				Node switchNode= graph.createNode(currentIndex);
				switchNode.isSwitchHeader= true;
				graph.addEdge(cNode, switchNode);
				cNode= null;

				int defaultOffset;
				int npairs;
				int offset;
				int remainder= bytes.getIndex() % 4;
				int noPadBytes= (remainder == 0) ? 0 : 4 - remainder;

				for (int i= 0; i < noPadBytes; i++)
				{
					byte b;

					if ((b= bytes.readByte()) != 0)
					{
						logger.warn("Padding byte != 0 in " + instructionType.getName() + ":" + b);
					}
				}

				defaultOffset= bytes.readInt();

				int low= 0;
				if (opcode == Const.LOOKUPSWITCH)
				{
					npairs= bytes.readInt();
					offset= bytes.getIndex() - 8 - noPadBytes - 1;
				}
				else
				{
					low= bytes.readInt();
					int high= bytes.readInt();
					npairs= high - low + 1;
					offset= bytes.getIndex() - 12 - noPadBytes - 1;
				}

				defaultOffset+= offset;

				switchNode.switchExpression= stack.pop();

				TreeMap caseGroups= new TreeMap();

				for (int i= 0; i < npairs; i++)
				{
					int key;
					if (opcode == Const.LOOKUPSWITCH)
					{
						key= bytes.readInt();
					}
					else
					{
						key= low + i;
					}

					SwitchEdge switchEdge= getOrCreateCaseGroup(switchNode, caseGroups, offset + bytes.readInt());
					switchEdge.expressions.add(NumberLiteral.create(new Integer(key)));
				}

				try
				{
					Node defaultNode= graph.createNode(defaultOffset);
					graph.addEdge(switchNode, defaultNode);
				}
				catch (Exception e)
				{
					setClassNotReversible(methodDecl);
				}

				instruction= new NoOperation();
				break;
			}

			case Const.CHECKCAST:
			{

				CastExpression cast= new CastExpression();
				int index= bytes.readUnsignedShort();
				ConstantClass c= (ConstantClass) constantPool.getConstant(index);
				ObjectType type= new ObjectType(c.getBytes(constantPool).replace('/', '.'));
				cast.setTypeBinding(type);
				cast.setExpression(stack.pop());
				instruction= cast;
				break;
			}

			case Const.INSTANCEOF:
			{

				int index= bytes.readUnsignedShort();
				InstanceofExpression ex= new InstanceofExpression();
				Expression objectref= stack.pop();
				ex.setLeftOperand(objectref);
				ConstantClass c= (ConstantClass) constantPool.getConstant(index);
				ObjectType type= new ObjectType(c.getBytes(constantPool).replace('/', '.'));
				ex.setRightOperand(type);
				ex.widen(objectref);
				instruction= ex;
				break;
			}

			case Const.ACONST_NULL:

				instruction= new NullLiteral();
				break;

			case Const.JSR:
			{

				instruction= new JumpSubRoutine(currentIndex + bytes.readShort());
				opStackDelta= 0;
				break;
			}

			case Const.JSR_W:
			{

				instruction= new JumpSubRoutine(currentIndex + bytes.readInt());
				break;
			}

			case Const.IFEQ:

				instruction= createConditional(currentIndex, InfixExpression.Operator.EQUALS, NumberLiteral.create(0));
				break;
			case Const.IFNE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.NOT_EQUALS, NumberLiteral.create(0));
				break;
			case Const.IFGE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.GREATER_EQUALS, NumberLiteral.create(0));
				break;
			case Const.IFGT:

				instruction= createConditional(currentIndex, InfixExpression.Operator.GREATER, NumberLiteral.create(0));
				break;
			case Const.IFLE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.LESS_EQUALS, NumberLiteral.create(0));
				break;
			case Const.IFLT:

				instruction= createConditional(currentIndex, InfixExpression.Operator.LESS, NumberLiteral.create(0));
				break;
			case Const.IFNONNULL:

				instruction= createConditional(currentIndex, InfixExpression.Operator.NOT_EQUALS, new NullLiteral());
				break;
			case Const.IFNULL:

				instruction= createConditional(currentIndex, InfixExpression.Operator.EQUALS, new NullLiteral());
				break;

			case Const.IF_ACMPEQ:

			case Const.IF_ICMPEQ:

				instruction= createConditional(currentIndex, InfixExpression.Operator.EQUALS);
				break;
			case Const.IF_ACMPNE:

			case Const.IF_ICMPNE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.NOT_EQUALS);
				break;
			case Const.IF_ICMPGE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.GREATER_EQUALS);
				break;
			case Const.IF_ICMPGT:

				instruction= createConditional(currentIndex, InfixExpression.Operator.GREATER);
				break;
			case Const.IF_ICMPLE:

				instruction= createConditional(currentIndex, InfixExpression.Operator.LESS_EQUALS);
				break;
			case Const.IF_ICMPLT:

				instruction= createConditional(currentIndex, InfixExpression.Operator.LESS);
				break;

			case Const.LCMP:

			case Const.FCMPL:

			case Const.FCMPG:

			case Const.DCMPL:

			case Const.DCMPG:
			{

				MethodBinding binding= MethodBinding.lookup("javascript.Utils", "cmp", "(DDI)I");
				MethodInvocation mi= new MethodInvocation(methodDecl, binding);

				Expression value2= stack.pop();
				mi.addArgument(stack.pop());
				mi.addArgument(value2);

				int gORl= 0;
				if (instructionType.getName().endsWith("g"))
					gORl= 1;
				else if (instructionType.getName().endsWith("l"))
					gORl= -1;
				mi.addArgument(NumberLiteral.create(gORl));

				instruction= mi;

				break;
			}

			case Const.GOTO:
			{

				instruction= new Jump(currentIndex + bytes.readShort());
				break;
			}

			case Const.GOTO_W:
			{

				instruction= new Jump(currentIndex + bytes.readInt());
				break;
			}

			case Const.NEW:
			{

				ConstantClass c= (ConstantClass) constantPool.getConstant(bytes.readUnsignedShort());
				ObjectType type= new ObjectType(c.getBytes(constantPool).replace('/', '.'));

				instruction= new ClassInstanceCreation(type);
			}
				break;

			case Const.NEWARRAY:
			{

				String componentSignature= BasicType.getType(bytes.readByte()).getSignature();

				List dimensions= new ArrayList();
				dimensions.add(stack.pop());
				ArrayCreation ac= new ArrayCreation(methodDecl, new ObjectType("[" + componentSignature), dimensions);
				instruction= ac;
				break;
			}

			case Const.ANEWARRAY:
			{

				ConstantClass c= (ConstantClass) constantPool.getConstant(bytes.readUnsignedShort());
				String componentSignature= c.getBytes(constantPool).replace('/', '.');
				Type arrayType;
				if (componentSignature.startsWith("["))
				{
					arrayType= new ObjectType("[" + componentSignature);
				}
				else
				{
					arrayType= new ObjectType("[L" + componentSignature + ";");
				}

				List dimensions= new ArrayList();
				dimensions.add(stack.pop());
				ArrayCreation ac= new ArrayCreation(methodDecl, arrayType, dimensions);
				instruction= ac;
				break;
			}

			case Const.MULTIANEWARRAY:
			{

				ConstantClass c= (ConstantClass) constantPool.getConstant(bytes.readUnsignedShort());
				ObjectType arrayType= new ObjectType(c.getBytes(constantPool).replace('/', '.'));

				int dimCount= bytes.readUnsignedByte();
				opStackDelta= 1 - dimCount;
				List dimensions= new ArrayList();
				for (int i= 0; i < dimCount; i++)
				{

					dimensions.add(0, stack.pop());
				}
				ArrayCreation ac= new ArrayCreation(methodDecl, arrayType, dimensions);
				instruction= ac;
				break;
			}

			case Const.PUTSTATIC:

			case Const.PUTFIELD:
			{

				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				Expression rhs= stack.pop();

				int index= bytes.readUnsignedShort();
				ConstantFieldref fieldRef= (ConstantFieldref) constantPool.getConstant(index, Constants.CONSTANT_Fieldref);

				FieldAccess fa= new FieldWrite();
				fa.setName(getFieldName(fieldRef));
				fa.setType(new ObjectType(fieldRef.getClass(constantPool)));
				fa.initialize(methodDecl);

				if (opcode == Const.PUTFIELD)
				{
					fa.setExpression(stack.pop());
				}

				a.setLeftHandSide(fa);
				a.setRightHandSide(rhs);

				instruction= a;
				break;
			}

			case Const.GETFIELD:
			{

				int index= bytes.readUnsignedShort();
				ConstantFieldref fieldRef= (ConstantFieldref) constantPool.getConstant(index, Constants.CONSTANT_Fieldref);

				Expression ex= stack.pop();
				FieldAccess fa= new FieldRead();
				fa.setType(new ObjectType(fieldRef.getClass(constantPool)));
				fa.setName(getFieldName(fieldRef));
				fa.setExpression(ex);
				fa.initialize(methodDecl);
				instruction= fa;
				break;
			}

			case Const.GETSTATIC:
			{

				int index= bytes.readUnsignedShort();
				ConstantFieldref fieldRef= (ConstantFieldref) constantPool.getConstant(index, Constants.CONSTANT_Fieldref);

				FieldAccess fa= new FieldRead();
				fa.setType(new ObjectType(fieldRef.getClass(constantPool)));
				fa.setName(getFieldName(fieldRef));
				fa.initialize(methodDecl);

				instruction= fa;
				break;
			}

			case Const.DUP:
			{

				dup1();
				instruction= stack.pop();
				break;
			}

			case Const.DUP2:

				if (form.getIndex() == 0)
				{
					dup2();
					instruction= stack.pop();
				}
				else
				{
					dup1();
					instruction= stack.pop();
				}
				break;

			case Const.DUP_X1:
			{

				dup1();
				stack.rotate(2);
				instruction= stack.pop();
				break;
			}

			case Const.DUP_X2:
			{

				if (form.getIndex() == 0)
				{
					dup1();
					stack.rotate(3);
				}
				else
				{
					dup1();
					stack.rotate(2);
				}
				instruction= stack.pop();
				break;
			}

			case Const.DUP2_X1:

				if (form.getIndex() == 0)
				{
					dup2();
					stack.rotate(4);
					stack.rotate(4);
				}
				else
				{
					dup1();
					stack.rotate(2);
				}
				instruction= stack.pop();
				break;

			case Const.DUP2_X2:

				if (form.getIndex() == 0)
				{
					dup2();
					stack.rotate(5);
					stack.rotate(5);
				}
				else if (form.getIndex() == 1)
				{
					dup1();
					stack.rotate(3);
				}
				else if (form.getIndex() == 2)
				{
					dup2();
					stack.rotate(4);
					stack.rotate(4);
				}
				else
				{
					dup1();
					stack.rotate(2);
				}

				instruction= stack.pop();
				break;

			case Const.SWAP:
			{

				stack.rotate(1);
				instruction= new NoOperation();
				break;
			}

			case Const.I2S:

			case Const.I2F:

			case Const.L2I:

			case Const.F2I:

			case Const.F2L:

			case Const.L2F:

			case Const.L2D:

			case Const.D2I:

			case Const.D2L:

			case Const.D2F:

			case Const.I2B:

			case Const.I2C:

				instruction= new PrimitiveCast(opcode, stack.pop(), form.getResultType());
				break;

			case Const.I2L:

				stack.peek().setTypeBinding(Type.LONG);
				instruction= new NoOperation();
				break;
			case Const.I2D:

			case Const.F2D:

				stack.peek().setTypeBinding(Type.DOUBLE);
				instruction= new NoOperation();
				break;

			case Const.INEG:

			case Const.LNEG:

			case Const.FNEG:

			case Const.DNEG:

				instruction= createPrefix(PrefixExpression.MINUS, stack.pop(), form.getResultType());
				break;

			case Const.ISHR:

			case Const.LSHR:

				instruction= createInfixRightLeft(InfixExpression.Operator.RIGHT_SHIFT_SIGNED, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.ISHL:

			case Const.LSHL:

				instruction= createInfixRightLeft(InfixExpression.Operator.LEFT_SHIFT, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IUSHR:

			case Const.LUSHR:

				instruction= createInfixRightLeft(InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IADD:

			case Const.LADD:

			case Const.FADD:

			case Const.DADD:

				instruction= createInfixRightLeft(InfixExpression.Operator.PLUS, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.ISUB:

			case Const.LSUB:

			case Const.FSUB:

			case Const.DSUB:

				instruction= createInfixRightLeft(InfixExpression.Operator.MINUS, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IMUL:

			case Const.LMUL:

			case Const.FMUL:

			case Const.DMUL:

				instruction= createInfixRightLeft(InfixExpression.Operator.TIMES, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IDIV:

			case Const.LDIV:

			case Const.FDIV:

			case Const.DDIV:

				instruction= createInfixRightLeft(InfixExpression.Operator.DIVIDE, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IREM:

			case Const.LREM:

			case Const.FREM:

			case Const.DREM:

				instruction= createInfixRightLeft(InfixExpression.Operator.REMAINDER, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IXOR:

			case Const.LXOR:

				instruction= createInfixRightLeft(InfixExpression.Operator.XOR, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IAND:

			case Const.LAND:

				instruction= createInfixRightLeft(InfixExpression.Operator.AND, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IOR:

			case Const.LOR:

				instruction= createInfixRightLeft(InfixExpression.Operator.OR, stack.pop(), stack.pop(), form.getResultType());
				break;

			case Const.IINC:
			{

				boolean isWide= wide;
				int index= readUnsigned();

				wide= isWide;
				int constByte= readSigned();

				VariableBinding reference= createVariableBinding(index, Type.INT, true);
				reference.setField(false);

				Assignment assign= new Assignment(Assignment.Operator.PLUS_ASSIGN);
				assign.setLeftHandSide(reference);
				assign.setRightHandSide(NumberLiteral.create(new Integer(constByte)));
				instruction= assign;
				break;
			}

			case Const.ARRAYLENGTH:
			{

				Expression arrayRef= stack.pop();
				FieldAccess access= new FieldRead();
				access.setExpression(arrayRef);
				access.setName("length");

				instruction= access;
				break;
			}

			case Const.WIDE:

				wide= true;
				return new NoOperation();

			case Const.ILOAD_0:

			case Const.ILOAD_1:

			case Const.ILOAD_2:

			case Const.ILOAD_3:
			{

				VariableBinding reference= createVariableBinding(opcode - Const.ILOAD_0, Type.INT, false);
				reference.setField(false);
				instruction= reference;
				break;
			}

			case Const.LLOAD_0:

			case Const.LLOAD_1:

			case Const.LLOAD_2:

			case Const.LLOAD_3:
			{

				VariableBinding reference= createVariableBinding(opcode - Const.LLOAD_0, Type.LONG, false);
				reference.setField(false);
				instruction= reference;
				break;
			}

			case Const.FLOAD_0:

			case Const.FLOAD_1:

			case Const.FLOAD_2:

			case Const.FLOAD_3:
			{

				VariableBinding reference= createVariableBinding(opcode - Const.FLOAD_0, Type.FLOAT, false);
				reference.setField(false);
				instruction= reference;
				break;
			}

			case Const.DLOAD_0:

			case Const.DLOAD_1:

			case Const.DLOAD_2:

			case Const.DLOAD_3:
			{

				VariableBinding reference= createVariableBinding(opcode - Const.DLOAD_0, Type.DOUBLE, false);
				reference.setField(false);
				instruction= reference;
				break;
			}

			case Const.ALOAD_0:

			case Const.ALOAD_1:

			case Const.ALOAD_2:

			case Const.ALOAD_3:
			{

				if (opcode == Const.ALOAD_0 && !Modifier.isStatic(methodDecl.getAccess()))
				{
					ThisExpression reference= new ThisExpression();
					instruction= reference;
				}
				else
				{
					VariableBinding reference= createVariableBinding(opcode - Const.ALOAD_0, Type.OBJECT, false);
					reference.setField(true);
					instruction= reference;
				}
				break;
			}

			case Const.ILOAD:

			case Const.LLOAD:

			case Const.FLOAD:

			case Const.DLOAD:
			{

				VariableBinding reference= createVariableBinding(readUnsigned(), form.getResultType(), false);
				reference.setField(false);
				instruction= reference;
				break;
			}

			case Const.ALOAD:
			{

				VariableBinding reference= createVariableBinding(readUnsigned(), Type.OBJECT, false);
				reference.setField(true);
				instruction= reference;
				break;
			}

			case Const.BALOAD:

			case Const.CALOAD:

			case Const.SALOAD:

			case Const.IALOAD:

			case Const.LALOAD:

			case Const.FALOAD:

			case Const.DALOAD:

			case Const.AALOAD:
			{

				Expression index= stack.pop();
				Expression arrayRef= stack.pop();
				ArrayAccess aa;
				aa= new ArrayAccess();
				aa.setTypeBinding(form.getResultType());
				aa.setArray(arrayRef);
				aa.setIndex(index);

				instruction= aa;
				break;
			}

			case Const.BASTORE:

			case Const.CASTORE:

			case Const.SASTORE:

			case Const.IASTORE:

			case Const.LASTORE:

			case Const.FASTORE:

			case Const.DASTORE:

			case Const.AASTORE:
			{

				Expression value= stack.pop();
				Expression index= stack.pop();
				Expression arrayRef= stack.pop();
				if (arrayRef instanceof ArrayCreation)
				{
					ArrayCreation ac= (ArrayCreation) arrayRef;
					if (ac.getInitializer() == null)
					{
						ac.setInitializer(new ArrayInitializer());
					}
					ac.getInitializer().getExpressions().add(value);
					instruction= new NoOperation();
					break;
				}
				Assignment a= new Assignment(Assignment.Operator.ASSIGN);

				ArrayAccess aa;
				aa= new ArrayAccess();
				aa.setArray(arrayRef);
				aa.setIndex(index);

				a.setLeftHandSide(aa);
				a.setRightHandSide(value);
				instruction= a;
				break;
			}

			case Const.DSTORE:

			case Const.DSTORE_0:

			case Const.DSTORE_1:

			case Const.DSTORE_2:

			case Const.DSTORE_3:
			{

				int index;
				if (opcode == Const.DSTORE)
				{
					index= readUnsigned();
				}
				else
				{
					index= opcode - Const.DSTORE_0;
				}
				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				VariableBinding reference= createVariableBinding(index, Type.DOUBLE, true);
				reference.setField(false);
				a.setLeftHandSide(reference);
				a.setRightHandSide(stack.pop());
				instruction= a;
				break;
			}

			case Const.FSTORE:

			case Const.FSTORE_0:

			case Const.FSTORE_1:

			case Const.FSTORE_2:

			case Const.FSTORE_3:
			{

				int index;
				if (opcode == Const.FSTORE)
				{
					index= readUnsigned();
				}
				else
				{
					index= opcode - Const.FSTORE_0;
				}
				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				VariableBinding reference= createVariableBinding(index, Type.FLOAT, true);
				reference.setField(false);
				a.setLeftHandSide(reference);
				a.setRightHandSide(stack.pop());
				instruction= a;
				break;
			}

			case Const.ISTORE:

			case Const.ISTORE_0:

			case Const.ISTORE_1:

			case Const.ISTORE_2:

			case Const.ISTORE_3:
			{

				int index;
				if (opcode == Const.ISTORE)
				{
					index= readUnsigned();
				}
				else
				{
					index= opcode - Const.ISTORE_0;
				}
				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				VariableBinding reference= createVariableBinding(index, Type.INT, true);
				reference.setField(false);
				a.setLeftHandSide(reference);
				a.setRightHandSide(stack.pop());
				instruction= a;
				break;
			}

			case Const.LSTORE:

			case Const.LSTORE_0:

			case Const.LSTORE_1:

			case Const.LSTORE_2:

			case Const.LSTORE_3:
			{

				int index;
				if (opcode == Const.LSTORE)
				{
					index= readUnsigned();
				}
				else
				{
					index= opcode - Const.LSTORE_0;
				}
				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				VariableBinding reference= createVariableBinding(index, Type.LONG, true);
				reference.setField(false);
				a.setLeftHandSide(reference);
				a.setRightHandSide(stack.pop());
				instruction= a;
				break;
			}

			case Const.ASTORE:

			case Const.ASTORE_0:

			case Const.ASTORE_1:

			case Const.ASTORE_2:

			case Const.ASTORE_3:
			{

				Assignment a= new Assignment(Assignment.Operator.ASSIGN);
				int index;
				if (opcode == Const.ASTORE)
				{
					index= readUnsigned();
				}
				else
				{
					index= (opcode - Const.ASTORE_0);
				}
				VariableBinding reference= createVariableBinding(index, Type.OBJECT, true);
				a.setLeftHandSide(reference);

				if (stack.size() > 0)
				{
					a.setRightHandSide(stack.pop());
				}
				instruction= a;
				break;
			}

			case Const.ATHROW:
			{

				ThrowStatement throwStmt= new ThrowStatement();
				throwStmt.setExpression(stack.pop());
				instruction= throwStmt;
				break;
			}

			case Const.ICONST_M1:

			case Const.ICONST_0:

			case Const.ICONST_1:

			case Const.ICONST_2:

			case Const.ICONST_3:

			case Const.ICONST_4:

			case Const.ICONST_5:

				instruction= NumberLiteral.create(new Integer(-1 + opcode - Const.ICONST_M1));
				break;

			case Const.LCONST_0:

			case Const.LCONST_1:

				instruction= NumberLiteral.create(new Long(opcode - Const.LCONST_0));
				break;

			case Const.FCONST_0:

			case Const.FCONST_1:

			case Const.FCONST_2:

				instruction= NumberLiteral.create(new Float(opcode - Const.FCONST_0));
				break;

			case Const.DCONST_0:

			case Const.DCONST_1:

				instruction= NumberLiteral.create(new Double(opcode - Const.DCONST_0));
				break;

			case Const.BIPUSH:
			{

				NumberLiteral literal= NumberLiteral.create(new Byte(bytes.readByte()));
				instruction= literal;
				break;
			}

			case Const.SIPUSH:
			{

				NumberLiteral il= NumberLiteral.create(new Short(bytes.readShort()));
				instruction= il;
				break;
			}

			case Const.LDC:

			case Const.LDC_W:

			case Const.LDC2_W:
			{

				int index;
				if (opcode == Const.LDC)
				{
					index= bytes.readUnsignedByte();
				}
				else
				{
					index= bytes.readUnsignedShort();
				}
				Constant constant= constantPool.getConstant(index);

				if (opcode == Const.LDC2_W && (constant.getTag() != Constants.CONSTANT_Double && constant.getTag() != Constants.CONSTANT_Long))
					throw new RuntimeException("LDC2_W must load long or double");

				if (constant.getTag() == Constants.CONSTANT_Integer)
				{
					instruction= NumberLiteral.create(new Integer(((ConstantInteger) constant).getBytes()));
				}
				else if (constant.getTag() == Constants.CONSTANT_Float)
				{
					instruction= NumberLiteral.create(new Float(((ConstantFloat) constant).getBytes()));
				}
				else if (constant.getTag() == Constants.CONSTANT_Long)
				{
					instruction= NumberLiteral.create(new Long(((ConstantLong) constant).getBytes()));
				}
				else if (constant.getTag() == Constants.CONSTANT_Double)
				{
					instruction= NumberLiteral.create(new Double(((ConstantDouble) constant).getBytes()));
				}
				else if (constant.getTag() == Constants.CONSTANT_Utf8)
				{
					instruction= new StringLiteral(((ConstantUtf8) constant).getBytes());
				}
				else if (constant.getTag() == Constants.CONSTANT_String)
				{
					int k= ((ConstantString) constant).getStringIndex();
					constant= constantPool.getConstant(k, Constants.CONSTANT_Utf8);
					instruction= new StringLiteral(((ConstantUtf8) constant).getBytes());
				}
				else if (constant.getTag() == Constants.CONSTANT_Class)
				{
					Signature signature= Project.getSingleton().getSignature(((ConstantClass) constant).getBytes(constantPool));
					instruction= new ClassLiteral(signature);
				}
				else
				{
					throw new RuntimeException("Cannot handle constant tag: " + constant.getTag());
				}
				break;
			}

			case Const.RET:
			{

				int index= readUnsigned();
				ReturnStatement r= new ReturnStatement(currentIndex, currentIndex);
				r.setExpression(createVariableBinding(index, Type.INT, false));
				instruction= r;
				break;
			}

			case Const.RETURN:

			case Const.IRETURN:

			case Const.FRETURN:

			case Const.LRETURN:

			case Const.DRETURN:

			case Const.ARETURN:
			{

				ReturnStatement r= new ReturnStatement(currentIndex, currentIndex);
				if (opcode != Const.RETURN)
				{
					r.setExpression(stack.pop());
				}
				instruction= r;
				break;
			}

			case Const.POP:

			case Const.POP2:
			{
				if (opcode == Const.POP2 && form.getIndex() == 1)
				{
					ASTNode a= stack.pop();
					//			cNode.block.appendChild(a);
					a= stack.pop();
					//			cNode.block.appendChild(a);
					//		    throw new UnsupportedOperationException("InstructionType " + instructionType.getName() + " not supported");
				}
				else
				{
					ASTNode a= stack.pop();
					if (!(a instanceof VariableBinding))
					{

						// be an ASTNode,
						// because it has no location.
						cNode.block.appendChild(a);
					}
				}
				instruction= new NoOperation();
				break;
			}

			case Const.NOP:
				// Format: nop
				// Operand stack: ... -> ...
				return new NoOperation();

			case Const.XXXUNUSEDXXX:
				// Format: xxxunusedxxx
				// Operand stack: ... -> ...
				logger.info("Byte code contains unused operation (Ignored)");
				return new NoOperation();

			case Const.INVOKEINTERFACE:
				// Format: invokeinterface, index(short), count(byte), 0(byte)
				// Operand stack: ..., objectref(), arg1(), ...(), argN() -> ...
			case Const.INVOKESPECIAL:
				// Format: invokespecial
				// Operand stack: ..., objectref(), arg1(), ...(), argN() -> ...
			case Const.INVOKEVIRTUAL:
				// Format: invokevirtual
				// Operand stack: ..., objectref(), arg1(), ...(), argN() -> ...
			case Const.INVOKESTATIC:
			{
				// Format: invokestatic, index(short)
				// Operand stack: ..., arg1(), ...(), argN() -> ...
				int index= bytes.readUnsignedShort();
				MethodBinding methodBinding= MethodBinding.lookup(index, constantPool);
				MethodInvocation invocation= new MethodInvocation(methodDecl, methodBinding);

				// Processor.getLogger().finer(method.getName() + "->" +
				// invocation.binding);

				int nArgs= methodBinding.getParameterTypes().length;
				int kk= stack.size() - nArgs;
				for (int i= 0; i < nArgs; i++)
				{
					Expression arg= (Expression) stack.get(kk);
					stack.remove(kk);
					invocation.addArgument(arg);
				}

				opStackDelta= -nArgs;

				if (opcode == Const.INVOKEVIRTUAL || opcode == Const.INVOKESPECIAL || opcode == Const.INVOKEINTERFACE)
				{
					opStackDelta--;
					invocation.setExpression(stack.pop());
				}
				else
				{ // INVOKESTATIC
					// Name name = new Name(method.getClassName());
					// invocation.setExpression(name);
				}

				if (methodBinding.getReturnType() != Type.VOID)
				{
					opStackDelta++;
				}

				if (opcode == Const.INVOKEINTERFACE)
				{
					bytes.readUnsignedByte(); // historical, redundant number of
					// arguments.
					bytes.readUnsignedByte(); // Last byte is a reserved space.
				}
				else if (opcode == Const.INVOKESPECIAL)
				{
					invocation.isSpecial= true;
				}

				// if (opcode==Const.INVOKESPECIAL && stack.size() > 0 &&
				// stack.peek() instanceof ClassInstanceCreation &&
				// methodBinding.getName().equals("")) {
				// ClassInstanceCreation cic = (ClassInstanceCreation) stack.pop();
				// List args = invocation.getArguments();
				// for (int i=0; i ...
				SynchronizedBlock sb= new SynchronizedBlock();
				sb.monitor= stack.pop();
				sb.widen(sb.monitor);
				sb.setEndIndex(currentIndex);
				instruction= sb;
				break;
			}
			case Const.MONITOREXIT:
				// Format: monitorexit
				// Operand stack: ..., objectref() -> ...
				instruction= new NoOperation();
				instruction.widen(stack.pop());
				instruction.setEndIndex(currentIndex);
				break;

			default:
				throw new UnsupportedOperationException("InstructionType " + instructionType.getName() + " not supported");
				// break;
		}

		if (opcode != Const.WIDE && wide)
			throw new RuntimeException("Expected wide operation");

		instruction.setStackDelta(opStackDelta);
		if (opcode < Const.DUP || opcode > Const.DUP2_X2)
		{
			instruction.leftWiden(currentIndex);
			instruction.rightWiden(bytes.getIndex() - 1);
		}
		currentNode= instruction;
		return instruction;
	}

	public static void setClassNotReversible(MethodDeclaration methodDeclaration)
	{
		ObjectType declaringClass= methodDeclaration.getMethodBinding().getDeclaringClass();
		Log.getLogger().debug("Not reversible method: " + methodDeclaration.getMethodBinding().getName() + " in: " + declaringClass);
		ClassUnit classUnit= Project.getSingleton().getClassUnit(declaringClass.getClassName());
		classUnit.addNotReversibleMethod(extractMethodNameSignature(methodDeclaration.getMethodBinding()));
		//	classUnit.setReversible(false);
	}

	public static String extractMethodNameSignature(MethodBinding methodBinding)
	{
		return methodBinding.getName() + "#" + methodBinding.getSignature();
	}

	ConditionalBranch createConditional(int currentIndex, InfixExpression.Operator operator) throws IOException
	{
		ConditionalBranch c= new ConditionalBranch(currentIndex + bytes.readShort());
		InfixExpression be= new InfixExpression(operator);
		Expression rightOperand= stack.pop();
		be.setOperands(stack.pop(), rightOperand);
		c.setExpression(be);
		return c;
	}

	ConditionalBranch createConditional(int currentIndex, InfixExpression.Operator operator, Expression rightOperand) throws IOException
	{
		ConditionalBranch c= new ConditionalBranch(currentIndex + bytes.readShort());
		Expression leftOperand= stack.pop();

		if (leftOperand.getTypeBinding() != null && leftOperand.getTypeBinding() == Type.BOOLEAN)
		{
			if (operator == InfixExpression.Operator.EQUALS && NumberLiteral.isZero(rightOperand))
			{
				c.setExpression(Optimizer.negate(leftOperand));
			}
			else
			{
				c.setExpression(leftOperand);
			}
		}
		else
		{
			InfixExpression be= new InfixExpression(operator);
			be.setOperands(leftOperand, rightOperand);
			c.setExpression(be);
		}

		return c;
	}

	private String getFieldName(ConstantFieldref fieldRef)
	{
		ConstantNameAndType nameAndType= (ConstantNameAndType) constantPool.getConstant(fieldRef.getNameAndTypeIndex());
		return nameAndType.getName(constantPool);
	}

	public static String constantToString(Constant c, ConstantPool constantPool) throws ClassFormatException
	{
		String str;
		byte tag= c.getTag();

		switch (tag)
		{
			case Constants.CONSTANT_Class:
				str= Utility.compactClassName(((ConstantClass) c).getBytes(constantPool), false);
				break;

			case Constants.CONSTANT_String:
				str= "\"" + Utils.escape(((ConstantString) c).getBytes(constantPool)) + "\"";
				break;

			case Constants.CONSTANT_Utf8:
				str= ((ConstantUtf8) c).getBytes();
				break;
			case Constants.CONSTANT_Double:
				str= "" + ((ConstantDouble) c).getBytes();
				break;
			case Constants.CONSTANT_Float:
				str= "" + ((ConstantFloat) c).getBytes();
				break;
			case Constants.CONSTANT_Long:
				str= "" + ((ConstantLong) c).getBytes();
				break;
			case Constants.CONSTANT_Integer:
				str= "" + ((ConstantInteger) c).getBytes();
				break;

			case Constants.CONSTANT_NameAndType:
				str= ((ConstantNameAndType) c).getName(constantPool);
				break;

			case Constants.CONSTANT_InterfaceMethodref:
			case Constants.CONSTANT_Methodref:
			case Constants.CONSTANT_Fieldref:
				str= ((ConstantCP) c).getClass(constantPool);
				break;

			default: // Never reached
				throw new RuntimeException("Unknown constant type " + tag);
		}

		return str;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy