com.googlecode.dex2jar.v3.V3MethodAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.dex2jar.v3.V3MethodAdapter.java

Source

/*
 * Copyright (c) 2009-2012 Panxiaobo
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.dex2jar.v3;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.util.TraceMethodVisitor;

import com.googlecode.dex2jar.DexOpcodes;
import com.googlecode.dex2jar.DexType;
import com.googlecode.dex2jar.Method;
import com.googlecode.dex2jar.asm.LdcOptimizeAdapter;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.stmt.LabelStmt;
import com.googlecode.dex2jar.ir.stmt.Stmt;
import com.googlecode.dex2jar.ir.stmt.Stmt.ST;
import com.googlecode.dex2jar.ir.stmt.StmtList;
import com.googlecode.dex2jar.ir.ts.ArrayNullPointerTransformer;
import com.googlecode.dex2jar.ir.ts.CleanLabel;
import com.googlecode.dex2jar.ir.ts.EndRemover;
import com.googlecode.dex2jar.ir.ts.ExceptionHandlerCurrectTransformer;
import com.googlecode.dex2jar.ir.ts.ExceptionHandlerTrim;
import com.googlecode.dex2jar.ir.ts.FixVar;
import com.googlecode.dex2jar.ir.ts.LocalRemove;
import com.googlecode.dex2jar.ir.ts.LocalSplit;
import com.googlecode.dex2jar.ir.ts.LocalType;
import com.googlecode.dex2jar.ir.ts.TopologicalSort;
import com.googlecode.dex2jar.ir.ts.Transformer;
import com.googlecode.dex2jar.ir.ts.ZeroTransformer;
import com.googlecode.dex2jar.v3.AnnotationNode.Item;
import com.googlecode.dex2jar.visitors.DexAnnotationAble;
import com.googlecode.dex2jar.visitors.DexAnnotationVisitor;
import com.googlecode.dex2jar.visitors.DexCodeVisitor;
import com.googlecode.dex2jar.visitors.DexMethodVisitor;

/**
 * @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a>
 * @version $Rev$
 */
public class V3MethodAdapter implements DexMethodVisitor, Opcodes {
    protected static Transformer topologicalSort = new TopologicalSort();
    private static final Logger log = Logger.getLogger(V3MethodAdapter.class.getName());
    protected static Transformer[] tses = new Transformer[] { new EndRemover(),
            new ExceptionHandlerCurrectTransformer(), new ZeroTransformer(), new ArrayNullPointerTransformer(),
            new FixVar(), new CleanLabel(), new LocalSplit(), new LocalRemove(), new LocalType(),
            new ExceptionHandlerTrim() };
    static {
        log.log(Level.CONFIG, "InsnList.check=false");
        // Optimize Tree Analyzer
        InsnList.check = false;
    }

    /**
     * index LabelStmt for debug
     * 
     * @param list
     */
    protected static void indexLabelStmt4Debug(StmtList list) {
        int labelIndex = 0;
        for (Stmt stmt : list) {
            if (stmt.st == ST.LABEL) {
                ((LabelStmt) stmt).displayName = "L" + labelIndex++;
            }
        }
    }

    protected int accessFlags;
    protected DexExceptionHandler exceptionHandler;
    protected IrMethod irMethod;
    final protected Method method;
    final protected MethodNode methodNode = new MethodNode();
    protected AnnotationNode signatureAnnotation;
    protected AnnotationNode throwsAnnotation;
    protected int config;

    public V3MethodAdapter(int accessFlags, Method method, DexExceptionHandler exceptionHandler) {
        this(accessFlags, method, exceptionHandler, 0);
    }

    public V3MethodAdapter(int accessFlags, Method method, DexExceptionHandler exceptionHandler, int config) {
        super();
        this.method = method;
        // clear ACC_DECLARED_SYNCHRONIZED and ACC_CONSTRUCTOR from method flags
        final int cleanFlag = ~((DexOpcodes.ACC_DECLARED_SYNCHRONIZED | DexOpcodes.ACC_CONSTRUCTOR));
        this.accessFlags = accessFlags & cleanFlag;
        this.exceptionHandler = exceptionHandler;
        this.config = config;
        // issue 88, the desc must set before visitParameterAnnotation
        methodNode.desc = method.getDesc();
    }

    @SuppressWarnings("unchecked")
    protected void build() {
        List<String> exceptions = new ArrayList<String>();
        String signature = null;
        if (this.throwsAnnotation != null) {
            for (Item item : this.throwsAnnotation.items) {
                if (item.name.equals("value")) {
                    List<Object> values = (List<Object>) item.value;
                    for (Object obj : values) {
                        exceptions.add(Type.getType(((DexType) obj).desc).getInternalName());
                    }
                }
            }
        }
        if (this.signatureAnnotation != null) {
            signature = V3ClassAdapter.buildSignature(this.signatureAnnotation);
        }

        MethodNode methodNode = this.methodNode;
        methodNode.access = this.accessFlags;
        methodNode.name = method.getName();
        methodNode.desc = method.getDesc();
        methodNode.signature = signature;
        methodNode.exceptions = exceptions;
        methodNode.tryCatchBlocks = new ArrayList<Object>();
        methodNode.localVariables = new ArrayList<Object>();
    }

    protected void debug_dump(MethodNode methodNode) {
        TraceMethodVisitor tmv = new TraceMethodVisitor();
        methodNode.instructions.accept(tmv);
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (Object o : tmv.text) {
            sb.append(i++).append(o);
        }
        System.out.println(sb);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.dex2jar.visitors.DexMethodVisitor#visitAnnotation(java .lang .String, boolean)
     */
    @Override
    public DexAnnotationVisitor visitAnnotation(String name, boolean visible) {
        if (name.equals("Ldalvik/annotation/Signature;")) {
            this.signatureAnnotation = new AnnotationNode(name, visible);
            return this.signatureAnnotation;
        } else if (name.equals("Ldalvik/annotation/Throws;")) {
            this.throwsAnnotation = new AnnotationNode(name, visible);
            return this.throwsAnnotation;
        } else {
            AnnotationVisitor av = methodNode.visitAnnotation(name, visible);
            if (av != null) {
                return new Dex2AsmAnnotationAdapter(av);
            }
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.dex2jar.visitors.DexMethodVisitor#visitCode()
     */
    @Override
    public DexCodeVisitor visitCode() {
        IrMethod irMethod = new IrMethod();
        irMethod.access = accessFlags;
        irMethod.args = Type.getArgumentTypes(method.getDesc());
        irMethod.ret = Type.getType(method.getReturnType());
        irMethod.owner = Type.getType(method.getOwner());
        irMethod.name = method.getName();
        this.irMethod = irMethod;
        return new V3CodeAdapter(this.accessFlags, irMethod);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.dex2jar.visitors.DexMethodVisitor#visitEnd()
     */
    @Override
    public void visitEnd() {
        build();
        IrMethod irMethod = this.irMethod;
        if (irMethod != null) {
            try {
                if (irMethod.stmts.getSize() > 1) {
                    if (V3.DEBUG) {
                        indexLabelStmt4Debug(irMethod.stmts);
                        for (Transformer ts : tses) {
                            ts.transform(irMethod);
                            indexLabelStmt4Debug(irMethod.stmts);
                        }
                        if (0 != (config & V3.TOPOLOGICAL_SORT)) {
                            topologicalSort.transform(irMethod);
                        }
                        indexLabelStmt4Debug(irMethod.stmts);
                    } else {
                        for (Transformer ts : tses) {
                            ts.transform(irMethod);
                        }
                        if (0 != (config & V3.TOPOLOGICAL_SORT)) {
                            topologicalSort.transform(irMethod);
                        }
                    }

                }
                if (0 != (config & V3.PRINT_IR)) {
                    indexLabelStmt4Debug(irMethod.stmts);
                    System.out.println(irMethod);
                }
                new IrMethod2AsmMethod(config).convert(irMethod, new LdcOptimizeAdapter(methodNode));
            } catch (Exception e) {
                if (this.exceptionHandler == null) {
                    throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
                } else {
                    this.exceptionHandler.handleMethodTranslateException(method, irMethod, methodNode, e);
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.dex2jar.visitors.DexMethodVisitor#visitParameterAnnotation (int)
     */
    @Override
    public DexAnnotationAble visitParameterAnnotation(final int index) {
        return new DexAnnotationAble() {
            @Override
            public DexAnnotationVisitor visitAnnotation(String name, boolean visible) {
                AnnotationVisitor av = methodNode.visitParameterAnnotation(index, name, visible);
                if (av != null) {
                    return new Dex2AsmAnnotationAdapter(av);
                }
                return null;
            }
        };
    }

}