Package ru.andrew.jclazz.decompiler.engine.blocks

Source Code of ru.andrew.jclazz.decompiler.engine.blocks.Block

package ru.andrew.jclazz.decompiler.engine.blocks;

import java.util.Map.Entry;
import ru.andrew.jclazz.decompiler.engine.*;
import ru.andrew.jclazz.decompiler.engine.ops.*;
import ru.andrew.jclazz.decompiler.*;

import java.util.*;
import ru.andrew.jclazz.core.ClazzException;
import ru.andrew.jclazz.core.FieldDescriptor;
import ru.andrew.jclazz.core.attributes.LocalVariableTable;

public class Block implements CodeItem
{
    protected final String NL = System.getProperty("line.separator");

    protected List ops;
    protected long fakeStartByte;
    protected Block parent;
    private MethodSourceView m_info;
    protected String indent = "";
    protected MethodContext context;

    protected Block(Block parent)
    {
        this(parent, new ArrayList());
    }

    public Block(Block parent, List ops)
    {
        this.ops = ops;
        this.parent = parent;
        this.context = parent.context;

        if (parent != null)
        {
            this.m_info = parent.m_info;
        }
    }

    public Block(List ops, MethodSourceView m_info)
    {
        this.ops = ops;
        this.m_info = m_info;
        this.context = m_info.getMethodContext();
    }

    public MethodContext getMethodContext()
    {
        return context;
    }

    public void setParent(Block parent)
    {
        this.parent = parent;
    }

    public Block getParent()
    {
        return parent;
    }

    public void setOperations(List ops)
    {
        this.ops = ops;
    }

    public List getOperations()
    {
        return ops;
    }

    public String getIndent()
    {
        return indent;
    }

    public void setIndent(String indent)
    {
        this.indent = indent;
    }

    public long getFakeStartByte()
    {
        return fakeStartByte;
    }

    public void setFakeStartByte(long fakeStartByte)
    {
        this.fakeStartByte = fakeStartByte;
    }

    // Handling block operations by iterating

    private int ext_pos = 0;

    private static final int END_BLOCK_POS = Integer.MAX_VALUE;

    public boolean hasMoreOperations()
    {
        return ext_pos < ops.size();
    }

    public CodeItem next()
    {
        CodeItem item = (CodeItem) ops.get(ext_pos);
        ext_pos++;
        return item;
    }

    public void back()
    {
        ext_pos--;
    }

    public void seekEnd()
    {
        ext_pos = END_BLOCK_POS;
    }

    public void reset()
    {
        ext_pos = 0;
    }

    // Business methods

    public void postCreate()
    {
    }

    public void postProcess()
    {
    }

    public List createSubBlock(long startOp, long endOp, Block subblock)
    {
        List subops = new ArrayList();

        boolean moving = false;
        int pos = 0;
        while (pos < ops.size())
        {
            CodeItem citem = (CodeItem) ops.get(pos);
            if (citem.getStartByte() >= startOp) moving = true;
            if (citem.getStartByte() >= endOp) break;

            if (moving)
            {
                subops.add(citem);
                if (subblock != null && citem instanceof Block) ((Block) citem).setParent(subblock);
                ops.remove(pos);
                if (ext_pos > pos && pos != 0) ext_pos--;
            }
            else
            {
                pos++;
            }
        }

        if (subblock != null)
        {
            ops.add(pos, subblock);
            subblock.setOperations(subops);
            if (subops.isEmpty())
            {
                subblock.setFakeStartByte(startOp);
            }
            subblock.setParent(this);
            subblock.postCreate();
        }
        return subops;
    }

    public void addOperation(int index, CodeItem ci)
    {
        if (index <= ext_pos && ext_pos != END_BLOCK_POS) ext_pos++;
        ops.add(index, ci);

        if (ci instanceof Block)
        {
            ((Block) ci).setParent(this);
        }
    }

    public void addOperation(CodeItem ci, long beforeOperation)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            CodeItem ci0 = (CodeItem) ops.get(i);
            if (ci0.getStartByte() == beforeOperation)
            {
                addOperation(i, ci);
                return;
            }
        }
    }

    private CodeItem removeOperation(int pos)
    {
        if (pos <= ext_pos && ext_pos != 0 && ext_pos != END_BLOCK_POS) ext_pos--;
        return (CodeItem) ops.remove(pos);
    }

    public CodeItem removeLastOperation()
    {
        return ops.isEmpty() ? null : removeOperation(ops.size() - 1);
    }

    public CodeItem removeFirstOperation()
    {
        if (!ops.isEmpty())
        {
            return removeOperation(0);
        }
        return null;
    }

    public CodeItem removeOperation(long start_byte)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            if (((CodeItem) ops.get(i)).getStartByte() == start_byte)
            {
                if (i <= ext_pos && ext_pos != 0 && ext_pos != END_BLOCK_POS) ext_pos--;
                return (CodeItem) ops.remove(i);
            }
        }
        return null;
    }

    public CodeItem getOperationPriorTo(long start_byte)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            if (((CodeItem) ops.get(i)).getStartByte() >= start_byte)
            {
                if (i == 0) return null;
                return (CodeItem) ops.get(i - 1);
            }
        }
        return getLastOperation();
    }

    public CodeItem getOperationAfter(long start_byte)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            if (((CodeItem) ops.get(i)).getStartByte() > start_byte) return (CodeItem) ops.get(i);
        }
        return null;
    }

    public CodeItem getOperationByStartByte(long start_byte)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            if (((CodeItem) ops.get(i)).getStartByte() == start_byte) return (CodeItem) ops.get(i);
        }
        return null;
    }

    public OperationView removePriorPushOperation()
    {
        int start_pos = ext_pos != END_BLOCK_POS ? ext_pos - 2 : ops.size() - 1;
        for (int i = start_pos; i >= 0 ; i--)
        {
            if (ops.get(i) instanceof Block)
            {
                OperationView priorPush = getPriorPushFromSubblock((Block) ops.get(i));   // TODO why not remove
                if (priorPush != null) return priorPush;
            }
            else if (((OperationView) ops.get(i)).isPush())
            {
                if (ext_pos != END_BLOCK_POS) ext_pos--;
                return (OperationView) ops.remove(i);
            }
        }
        return null;
    }

    private OperationView getPriorPushFromSubblock(Block subblock)
    {
        subblock.seekEnd();
        return subblock.removePriorPushOperation();
    }

    public CodeItem removeCurrentOperation()
    {
        ext_pos--;
        return (CodeItem) ops.remove(ext_pos);
    }

    public OperationView getPriorPushOperation()
    {
        int start_pos = ext_pos != END_BLOCK_POS ? ext_pos - 2 : ops.size() - 1;
        for (int i = start_pos; i >= 0 ; i--)
        {
            if (ops.get(i) instanceof Block)
            {
                OperationView priorPush = getPriorPushFromSubblock((Block) ops.get(i));
                if (priorPush != null) return priorPush;
            }
            else if (((OperationView) ops.get(i)).isPush())
            {
                return (OperationView) ops.get(i);
            }
        }
        return null;
    }

    public CodeItem getPreviousOperation()
    {
        return (CodeItem) (ext_pos - 2 >= 0 ? ops.get(ext_pos - 2) : null);
    }

    public CodeItem removePreviousOperation()
    {
        if (ext_pos - 2 >= 0)
        {
            CodeItem ci = (CodeItem) ops.remove(ext_pos - 2);
            ext_pos--;
            return ci;
        }
        return null;
    }

    public CodeItem getNextOperation()
    {
        if (hasMoreOperations())
        {
            return (CodeItem) ops.get(ext_pos);
        }
        return null;
    }

    public void replaceOperation(long start_byte, CodeItem newop)
    {
        for (int i = 0; i < ops.size(); i++)
        {
            if (((CodeItem) ops.get(i)).getStartByte() == start_byte)
            {
                ops.remove(i);
                ops.add(i, newop);
                return;
            }
        }
    }

    public void replaceCurrentOperation(CodeItem newop)
    {
        if (ext_pos > 0 && ext_pos != END_BLOCK_POS)
        {
            if (newop != null)
            {
                ops.set(ext_pos - 1, newop);
                if (newop instanceof Block) ((Block) newop).setParent(this);
            }
            else
            {
                ops.remove(ext_pos - 1);
                ext_pos--;
            }
        }
    }

    public void truncate(long fromStartByte)
    {
        Iterator it = ops.iterator();
        while (it.hasNext())
        {
            CodeItem ci = (CodeItem) it.next();
            if (ci.getStartByte() >= fromStartByte) it.remove();
        }
    }

    public MethodSourceView getMethodView()
    {
        Block preBlock = this;
        while (preBlock.parent != null)
        {
            preBlock = preBlock.parent;
        }
        return preBlock.m_info;
    }

    public boolean isEmpty()
    {
        return ops == null || ops.isEmpty();
    }

    public int size()
    {
        return ops == null ? 0 : ops.size();
    }

    public int printedSize()
    {
        int s = 0;
        for (int i = 0; i < ops.size(); i++)
        {
            if (ops.get(i) instanceof Block || ((OperationView) ops.get(i)).isPrintable())
            {
                s++;
            }
        }
        return s;
    }

    public CodeItem getFirstOperation()
    {
        return ops.isEmpty() ? null : (CodeItem) ops.get(0);
    }

    public CodeItem getLastOperation()
    {
        return ops.isEmpty() ? null : (CodeItem) ops.get(ops.size() - 1);
    }

    public CodeItem getFirstPrintedOperation()
    {
        for (int i = 0; i < ops.size(); i++)
        {
            CodeItem citem = (CodeItem) ops.get(i);
            if (citem instanceof Block || ((OperationView) citem).isPrintable())
            {
                return citem;
            }
        }
        return null;
    }

    public CodeItem getLastPrintedOperation()
    {
        for (int i = ops.size() - 1; i >= 0; i--)
        {
            CodeItem citem = (CodeItem) ops.get(i);
            if (citem instanceof Block || ((OperationView) citem).isPrintable())
            {
                return citem;
            }
        }
        return null;
    }

    public long getStartByte()
    {
        if (ops == null || ops.isEmpty())
        {
            return fakeStartByte;
        }
        return ((CodeItem) ops.get(0)).getStartByte();
    }

    public String getSource()
    {
        return indent + "{" + NL + getOperationsSource() + indent + "}" + NL;
    }

    public String getOperationsSource()
    {
        return getOperationsSource(-1);
    }

    public String getOperationsSource(int endByte)
    {
        StringBuffer sb = new StringBuffer();
        boolean withLN = "yes".equals(getMethodView().getClazzView().getDecompileParameter(ClazzSourceView.WITH_LINE_NUMBERS)) &&
                         (getMethodView().getMethod().getCodeBlock() != null) &&
                         (getMethodView().getMethod().getLineNumberTable() != null);
       
        for (Iterator i = ops.iterator(); i.hasNext();)
        {
            CodeItem citem = (CodeItem) i.next();
            if (endByte != -1 && citem.getStartByte() >= endByte) break;
            if (withLN &&
                (!(citem instanceof Block) ||
                       (citem instanceof IfBlock) ||
                       (citem instanceof Loop && (((Loop) citem).isPrintPrecondition()))) )
            {
                int instruction;
                if (citem instanceof Loop)
                {
                    Condition cond0 = (Condition) ((List) ((Loop) citem).getConditions().get(0)).get(0);
                    instruction = (int) cond0.getIfOperation().getStartByte();
                }
                else
                {
                    instruction = (int) citem.getStartByte();
                }
                int ln = getMethodView().getMethod().getLineNumberTable().getLineNumber(instruction);
                if (ln != -1)
                {
                    // TODO improve printing line numbers
                    sb.append(indent).append("    ").append("/* ").append(ln).append(" */");
                }
            }
            if (citem instanceof Block)
            {
                ((Block) citem).setIndent(indent + "    ");
                sb.append(((Block) citem).getSource());
            }
            else
            {
                OperationView ov = (OperationView) citem;
                if (ov.isPrintable())
                {
                    String opSource = ov.source2();
                    if (opSource != null) sb.append(indent).append("    ").append(opSource).append(";").append(NL);
                }
            }
        }
        return sb.toString();
    }

    protected String alias(String fqn)
    {
        return ImportManager.getInstance().importClass(fqn, getMethodView().getClazzView());
    }

    public void analyze(Block block)
    {
    }

    // Local Variables management

    protected Map lvars = new HashMap();    // var number > Map (start byte > LocalVariable)

    protected LocalVariable retrieve(Integer num, int start_byte)
    {
        Map lvs = (Map) lvars.get(num);
        if (lvs == null) return null;

        LocalVariable lv = null;
        for (Iterator i = lvs.entrySet().iterator(); i.hasNext();)
        {
            Map.Entry entry = (Entry) i.next();
            if (start_byte >= ((Integer) entry.getKey()).intValue())
            {
                lv = (LocalVariable) entry.getValue();
            }
        }

        return lv;
    }

    public LocalVariable getLocalVariable(int ivar, String type, int start_byte)
    {
        LocalVariable lv = retrieve(new Integer(ivar), start_byte);
        Block parentBlock = this;
        while ((lv == null) && (parentBlock != null))
        {
            lv = (LocalVariable) parentBlock.retrieve(new Integer(ivar), start_byte);
            parentBlock = parentBlock.parent;
        }

        LocalVariableTable.LocalVariable lv_debug = null;
        if (m_info.getMethod().getCodeBlock() != null && m_info.getMethod().getCodeBlock().getLocalVariableTable() != null)
        {
            lv_debug = m_info.getMethod().getCodeBlock().getLocalVariableTable().getLocalVariable(ivar, start_byte);
        }
        if (lv != null && lv_debug != null)
        {
            if (lv.getName() != null && !lv.getName().equals(lv_debug.name.getValue()))
            {
                // Reuse local variable
                lv = null;
            }
        }
        if (lv != null && type != null && !LocalVariable.UNKNOWN_TYPE.equals(lv.getType()) && !lv.getType().equals(type))
        {
            if (lv_debug != null)
            {
                try
                {
                    type = new FieldDescriptor(lv_debug.descriptor.getString()).getFQN();
                }
                catch (ClazzException e)
                {
                    throw new RuntimeException(e);
                }
            }

            if (!lv.isIsMethodArg() && !checkType(type, lv.getType()))
            {
                // Reuse local variable
                lv = null;
            }
        }
        if (lv != null && type != null && LocalVariable.UNKNOWN_TYPE.equals(lv.getType()))
        {
            lv.renewType(type);
        }
        if (lv == null)
        {
            lv = new LocalVariable(ivar, type, getMethodView());
            storeLVInBlock(ivar, lv, start_byte);
        }
        return lv;
    }

    protected void storeLVInBlock(int ivar, LocalVariable lv, int start_byte)
    {
        Block storeBlock = this;
        if (storeBlock instanceof Condition)
        {
            Block parent4cond = storeBlock.parent;
            if (parent4cond instanceof IfBlock)
            {
                storeBlock = parent4cond.parent;
            }
            if (parent4cond instanceof Loop)
            {
                if (((Loop) parent4cond).isBackLoop())
                {
                    storeBlock = parent4cond;
                }
                else
                {
                    storeBlock = parent4cond.parent;
                }
            }
        }

        Map lvs = (Map) storeBlock.lvars.get(new Integer(ivar));
        if (lvs == null)
        {
            lvs = new TreeMap();
            storeBlock.lvars.put(new Integer(ivar), lvs);
        }

        lvs.put(new Integer(start_byte), lv);
    }

    // Checks if fqn can be casted to fqnBase without special cast operator
    private boolean checkType(String fqn, String fqnBase)
    {
        if (fqn.equals(fqnBase)) return true;

        try
        {
            return widePrimitiveConversion(fqn, fqnBase);
        }
        catch (IllegalArgumentException iae)
        {
            // Continue check
        }

        // Widening Reference Conversions
        // Try to instantiate class
        try
        {
            Class fqnClass = Class.forName(fqn);
            Class fqnBaseClass = Class.forName(fqnBase);
            return fqnBaseClass.isAssignableFrom(fqnClass);
        }
        catch (ClassNotFoundException e)
        {
            // If can not instantiate then always return true
            return true;
        }
    }

    public static boolean widePrimitiveConversion(String type, String wideType)
    {
        if ("boolean".equals(wideType) && "int".equals(type)) return true;

        // Widening primitive conversions
        if ("byte".equals(type))
        {
            return "short".equals(wideType) || "int".equals(wideType) || "long".equals(wideType) ||
                   "float".equals(wideType) || "double".equals(wideType);
        }
        else if ("short".equals(type))
        {
            return "int".equals(wideType) || "long".equals(wideType) ||
                   "float".equals(wideType) || "double".equals(wideType);
        }
        else if ("char".equals(type))
        {
            return "int".equals(wideType) || "long".equals(wideType) ||
                   "float".equals(wideType) || "double".equals(wideType);
        }
        else if ("int".equals(type))
        {
            return "long".equals(wideType) ||
                   "float".equals(wideType) || "double".equals(wideType);
        }
        else if ("long".equals(type))
        {
            return "float".equals(wideType) || "double".equals(wideType);
        }
        else if ("float".equals(type))
        {
            return "double".equals(wideType);
        }
        else if ("double".equals(type))
        {
            return false;
        }
        else if ("boolean".equals(type))
        {
            return false;
        }
        else if ("void".equals(type))
        {
            return false;
        }
        else
        {
            throw new IllegalArgumentException("Not a primitive type");
        }
    }

    public void analyze2(Block block)
    {
        analyze(block);
    }

    public void preanalyze(Block block)
    {
    }

    public void postanalyze(Block block)
    {
    }
}
TOP

Related Classes of ru.andrew.jclazz.decompiler.engine.blocks.Block

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.