Package com.dragome.compiler.parser

Source Code of com.dragome.compiler.parser.Pass1

/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>.

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<TryStatement> tryStatements= new ArrayList<TryStatement>();

  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<ExceptionHandler> 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<Node> 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<Node> activeNodes= new ArrayList<Node>();
    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<VariableDeclaration> tempDecls= new ArrayList<VariableDeclaration>();

  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<Integer, SwitchEdge> 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<Integer, SwitchEdge> caseGroups= new TreeMap<Integer, SwitchEdge>();

        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<ASTNode> dimensions= new ArrayList<ASTNode>();
        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<ASTNode> dimensions= new ArrayList<ASTNode>();
        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<ASTNode> dimensions= new ArrayList<ASTNode>();
        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("<init>")) {
        // ClassInstanceCreation cic = (ClassInstanceCreation) stack.pop();
        // List args = invocation.getArguments();
        // for (int i=0; i<args.size(); i++)
        // cic.addArgument((Expression) args.get(i));
        // cic.signature = method.getSignature();
        // //invocation.setExpression(cic.getType());
        // instruction = cic;
        // } else {
        // instruction = invocation;
        // }
        instruction= invocation;
        break;
      }

      case Const.MONITORENTER:
      {
        // Format: monitorenter
        // Operand stack: ..., objectref() -> ...
        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;
  }

}
TOP

Related Classes of com.dragome.compiler.parser.Pass1

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.