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

com.codename1.tools.translator.Parser Maven / Gradle / Ivy

There is a newer version: 7.0.164
Show newest version
/*
 * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Codename One designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *  
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Codename One through http://www.codenameone.com/ if you 
 * need additional information or have any questions.
 */

package com.codename1.tools.translator;

import java.io.*;
import java.util.*;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
import org.objectweb.asm.commons.JSRInlinerAdapter;

import com.codename1.tools.translator.bytecodes.LabelInstruction;

/**
 *
 * @author Shai Almog
 */
public class Parser extends ClassVisitor {
    private ByteCodeClass cls;
    private String clsName;
    private static String[] nativeSources;
    private static List classes = new ArrayList();
    public static void cleanup() {
    	nativeSources = null;
    	classes.clear();
    	LabelInstruction.cleanup();
    }
    public static void parse(File sourceFile) throws Exception {
        if(ByteCodeTranslator.verbose) {
            System.out.println("Parsing: " + sourceFile.getAbsolutePath());
        }
        ClassReader r = new ClassReader(new FileInputStream(sourceFile));
        /*if(ByteCodeTranslator.verbose) {
            System.out.println("Class: " + r.getClassName() + " derives from: " + r.getSuperName() + " interfaces: " + Arrays.asList(r.getInterfaces()));
        }*/
        Parser p = new Parser();
        
        p.clsName = r.getClassName().replace('/', '_').replace('$', '_');
        p.cls = new ByteCodeClass(p.clsName, r.getClassName());
        r.accept(p, ClassReader.EXPAND_FRAMES);
        
        classes.add(p.cls);
    }
    
    private static ByteCodeClass getClassByName(String name) {
        name = name.replace('/', '_').replace('$', '_');
        for(ByteCodeClass bc : classes) {
            if(bc.getClsName().equals(name)) {
                return bc;
            }
        }        
        return null;
    }
    
    private static void appendClassOffset(ByteCodeClass bc, List clsIds) {
        if(bc.getBaseClassObject() != null) {
            if(!clsIds.contains(bc.getBaseClassObject().getClassOffset())) {
                clsIds.add(bc.getBaseClassObject().getClassOffset());
                appendClassOffset(bc.getBaseClassObject(), clsIds);
            }
        }
        if(bc.getBaseInterfacesObject() != null) {
            for(ByteCodeClass c : bc.getBaseInterfacesObject()) {
                if(c != null && !clsIds.contains(c.getClassOffset())) {
                    clsIds.add(c.getClassOffset());
                    if(c.getBaseClassObject() != null) {
                        appendClassOffset(c, clsIds);
                    }
                }
            }
        }
    }

    private static ArrayList constantPool = new ArrayList();
    
    public static ByteCodeClass getClassObject(String name) {
        for(ByteCodeClass cls : classes) {
            if(cls.getClsName().equals(name)) {
                return cls;
            }
        }
        return null;
    }
    
    /**
     * Adds the given string to the hardcoded constant pool strings returns the offset in the pool
     */
    public static int addToConstantPool(String s) {
        int i = constantPool.indexOf(s);
        if(i < 0) {
            constantPool.add(s);
            return constantPool.size() - 1;
        }
        return i;
    }
    
    
    
    private static void generateClassAndMethodIndexHeader(File outputDirectory) throws Exception {
        int classOffset = 0;
        int methodOffset = 0;
        ArrayList methods = new ArrayList();
        for(ByteCodeClass bc : classes) {
            bc.setClassOffset(classOffset);
            classOffset++;
            
            methodOffset = bc.updateMethodOffsets(methodOffset);
            methods.addAll(bc.getMethods());
        }
        
        StringBuilder bld = new StringBuilder();
        StringBuilder bldM = new StringBuilder();
        bldM.append("#include \"cn1_class_method_index.h\"\n");
        bldM.append("#include \"cn1_globals.h\"\n\n");
        bld.append("#ifndef __CN1_CLASS_METHOD_INDEX_H__\n#define __CN1_CLASS_METHOD_INDEX_H__\n\n");
        
        
        bld.append("// maps to offsets in the constant pool below\nextern int classNameLookup[];\n");
        bldM.append("// maps to offsets in the constant pool below\nint classNameLookup[] = {");
        boolean first = true;
        for(ByteCodeClass bc : classes) {
            if(first) {
                bldM.append("\n    ");
            } else {
                bldM.append(",\n    ");
            }
            first = false;
            bldM.append(addToConstantPool(bc.getClsName().replace('_', '.')));
            bldM.append("");
        }
        bldM.append("};\n\n");
        
        for(ByteCodeClass bc : classes) {
            bld.append("#define cn1_class_id_");
            bld.append(bc.getClsName());
            bld.append(" ");
            bld.append(bc.getClassOffset());
            bld.append("\n");
        }
        
        int arrayId = classes.size() + 1;
        
        bld.append("#define cn1_array_start_offset ");
        bld.append(arrayId);
        bld.append("\n");
        
        // leave space for primitive arrays
        arrayId += 100;
        
        for(ByteCodeClass bc : classes) {
            bld.append("#define cn1_array_1_id_");
            bld.append(bc.getClsName());
            bld.append(" ");
            bld.append(arrayId);
            bld.append("\n");
            arrayId++;

            bld.append("#define cn1_array_2_id_");
            bld.append(bc.getClsName());
            bld.append(" ");
            bld.append(arrayId);
            bld.append("\n");
            arrayId++;

            bld.append("#define cn1_array_3_id_");
            bld.append(bc.getClsName());
            bld.append(" ");
            bld.append(arrayId);
            bld.append("\n");
            arrayId++;

            /*bld.append("#define cn1_array_4_id_");
            bld.append(bc.getClsName());
            bld.append(" ");
            bld.append(arrayId);
            bld.append("\n");
            arrayId++;*/
        }

        bld.append("\n\n");

        bld.append("// maps to offsets in the constant pool below\nextern int methodNameLookup[];\n");
        bldM.append("// maps to offsets in the constant pool below\nint methodNameLookup[] = {");
        first = true;
        for(BytecodeMethod m : methods) {
            if(first) {
                bldM.append("\n    ");
            } else {
                bldM.append(",\n    ");
            }
            first = false;
            bldM.append(addToConstantPool(m.getMethodName()));
            bldM.append("");
        }
        bldM.append("};\n\n");
        
        ArrayList instances = new ArrayList();
        int counter = 0;
        for(ByteCodeClass bc : classes) {
            /*bld.append("extern int classInstanceOfArr");
            bld.append(counter);
            bld.append("[];\n");*/
            bldM.append("int classInstanceOfArr");
            bldM.append(counter);
            bldM.append("[] = {");
            counter++;
            appendClassOffset(bc, instances);
            
            for(Integer i : instances) {
                bldM.append(i);
                bldM.append(", ");
            }
            instances.clear();
            bldM.append("-1};\n");
        }
        bld.append("extern int *classInstanceOf[];\n");
        bldM.append("int *classInstanceOf[");
        bldM.append(classes.size());
        bldM.append("] = {");
        first = true;
        counter = 0;
        for(ByteCodeClass bc : classes) {
            if(first) {
                bldM.append("\n    ");
            } else {
                bldM.append(",\n    ");
            }
            first = false;
            bldM.append("classInstanceOfArr");
            bldM.append(counter);
            counter++;
        }
        bldM.append("};\n\n");
        
        bld.append("#define CN1_CONSTANT_POOL_SIZE ");
        bld.append(constantPool.size());
        bld.append("\n\nextern const char * const constantPool[];\n");

        bldM.append("\n\nconst char * const constantPool[] = {\n");
        first = true;
        int offset = 0;
        for(String con : constantPool) {
            if(first) {
                bldM.append("\n    \"");
            } else {
                bldM.append(",\n    \"");
            }
            first = false;            
            try {
                bldM.append(encodeString(con));
            } catch(Throwable t) {
                t.printStackTrace();
                System.out.println("Error writing the constant pool string: '" + con + "'");
                System.exit(1);
            }
            bldM.append("\" /* ");
            bldM.append(offset);
            offset++;
            bldM.append(" */");
        }
        bldM.append("};\n\nint classListSize = ");
        bldM.append(classes.size());
        bldM.append(";\n");

        for(ByteCodeClass bc : classes) {
            bldM.append("extern struct clazz class__");
            bldM.append(bc.getClsName().replace('/', '_').replace('$', '_'));
            bldM.append(";\n");
        }
        bldM.append("\n\nstruct clazz* classesList[] = {");
        first = true;
        for(ByteCodeClass bc : classes) {
            if(first) {
                bldM.append("\n    ");
            } else {
                bldM.append(",\n    ");
            }
            first = false;
            bldM.append("    &class__");
            bldM.append(bc.getClsName().replace('/', '_').replace('$', '_'));
        }
        bldM.append("};\n\n\n");
        
        // generate the markStatics method
        for(ByteCodeClass bc : classes) {
            bc.appendStaticFieldsExtern(bldM);
        }        
        bldM.append("\n\nextern int recursionKey;\nvoid markStatics(CODENAME_ONE_THREAD_STATE) {\n    recursionKey++;\n");
        for(ByteCodeClass bc : classes) {
            bc.appendStaticFieldsMark(bldM);
        }        
        bldM.append("}\n\n");
        
        
        bld.append("\n\n#endif // __CN1_CLASS_METHOD_INDEX_H__\n");        
        
        FileOutputStream fos = new FileOutputStream(new File(outputDirectory, "cn1_class_method_index.h"));
        fos.write(bld.toString().getBytes("UTF-8"));
        fos.close();
        fos = new FileOutputStream(new File(outputDirectory, "cn1_class_method_index.m"));
        fos.write(bldM.toString().getBytes("UTF-8"));
        fos.close();
    }
    
    private static String encodeString(String con) {
        String str = con.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
        return encodeStringSlashU(str);
    }
    
    private static String encodeStringSlashU(String str) {
        int len = str.length();
        char[] chr = str.toCharArray();
        for(int iter = 0 ; iter < len ; iter++) {
            char c = chr[iter];
            if(c > 127 || c < 32) {
                // needs encoding... Verify there are no more characters to encode
                StringBuilder d = new StringBuilder();
                for(int internal = 0 ; internal < len ; internal++) {
                    c = chr[internal];
                    if(c > 127 || c < 32) {
                        d.append("~~u");
                        d.append(fourChars(Integer.toHexString(c)));
                    } else {
                        d.append(c);
                    }
                }
                return d.toString();
            }
        }
        return str;
    }
    
    private static String fourChars(String s) {
        switch(s.length()) {
            case 1: 
                return "000" + s;
            case 2: 
                return "00" + s;
            case 3: 
                return "0" + s;
        }
        return s;
    }
    
    public static void writeOutput(File outputDirectory) throws Exception {
        System.out.println("outputDirectory is: " + outputDirectory.getAbsolutePath() );
        if(ByteCodeClass.getMainClass()==null){
			System.out.println("Error main class is not defined. The main class name is expected to have a public static void main(String[]) method and it is assumed to reside in the com.package.name directory");
			System.exit(1);
		}
        String file = "Unknown File";
        try {
            for(ByteCodeClass bc : classes) {
                // special case for object
                if(bc.getClsName().equals("java_lang_Object")) {
                    continue;
                }
                file = bc.getClsName();
                bc.setBaseClassObject(getClassByName(bc.getBaseClass()));
                List lst = new ArrayList();
                for(String s : bc.getBaseInterfaces()) {
					ByteCodeClass bcode=getClassByName(s);
					if(bcode==null){
					  System.out.println("Error while working with the class: " + s+" file:"+file+" no class definition");
					} else {
						lst.add(getClassByName(s));
					}
                }
                bc.setBaseInterfacesObject(lst);
            }
            boolean foundNewUnitTests = true;
            while (foundNewUnitTests) {
                foundNewUnitTests = false;
                for (ByteCodeClass bc : classes) {
                    if (!bc.isUnitTest() && bc.getBaseClassObject() != null && bc.getBaseClassObject().isUnitTest()) {
                        bc.setIsUnitTest(true);
                        foundNewUnitTests = true;
                    }
                }
            }
            
            // load the native sources (including user native code) 
            // We need to load native sources before we clear any unmarked classes
            // because native source may be the only thing referencing a class,
            // and the class may be purged before it even has a shot.
            readNativeFiles(outputDirectory);

            for(ByteCodeClass bc : classes) {
                file = bc.getClsName();
                bc.updateAllDependencies();
            }
            ByteCodeClass.markDependencies(classes, nativeSources);
            Set unmarked = new HashSet(classes);
            classes = ByteCodeClass.clearUnmarked(classes);
            unmarked.removeAll(classes);
            int neliminated = 0;
            for (ByteCodeClass removedClass : unmarked) {
                removedClass.setEliminated(true);
                neliminated++;
            }

            // loop over methods and start eliminating the body of unused methods
            if (BytecodeMethod.optimizerOn) {
                System.out.println("Optimizer On: Removing unused methods and classes...");
                Date now = new Date();
                neliminated += eliminateUnusedMethods();
                Date later = new Date();
                long dif = later.getTime()-now.getTime();
                System.out.println("unusued Method cull removed "+neliminated+" methods in "+(dif/1000)+" seconds");
            }

            generateClassAndMethodIndexHeader(outputDirectory);

            boolean concatenate = "true".equals(System.getProperty("concatenateFiles", "false"));
            ConcatenatingFileOutputStream cos = concatenate ? new ConcatenatingFileOutputStream(outputDirectory) : null;

            for(ByteCodeClass bc : classes) {
                file = bc.getClsName();
                writeFile(bc, outputDirectory, cos);
            }
            if (cos != null) cos.realClose();

        } catch(Throwable t) {
            System.out.println("Error while working with the class: " + file);
            t.printStackTrace();
            if(t instanceof Exception) {
                throw (Exception)t;
            }
            if(t instanceof RuntimeException) {
                throw (RuntimeException)t;
            }
        }
        finally { cleanup(); }
    }
    
    private static void readNativeFiles(File outputDirectory) throws IOException {
        File[] mFiles = outputDirectory.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.getName().endsWith(".m");
            }
        });
        nativeSources = new String[mFiles.length];
        int size = 0;
        System.out.println(""+mFiles.length +" native files");
        for(int iter = 0 ; iter < mFiles.length ; iter++) { 
        	FileInputStream fi = new FileInputStream(mFiles[iter]);
            DataInputStream di = new DataInputStream(fi);
            int len = (int)mFiles[iter].length();
            size += len;
            byte[] dat = new byte[len];
            di.readFully(dat);
            fi.close();
            nativeSources[iter] = new String(dat, "UTF-8");
        }
        System.out.println("Native files total "+(size/1024)+"K");
        
    }
    
    private static int eliminateUnusedMethods() {
        return(eliminateUnusedMethods(false, 0));
    }

    private static int eliminateUnusedMethods(boolean forceFound, int depth) {
        int nfound = cullMethods();
        nfound += cullClasses(nfound>0 || forceFound, depth);
        return(nfound);
    }

    private static int cullMethods() {
    	int nfound = 0;
    	for(ByteCodeClass bc : classes) {
            bc.unmark();
            if(bc.isIsInterface() || bc.getBaseClass() == null) {
                continue;
            }
            for(BytecodeMethod mtd : bc.getMethods()) {
                if(mtd.isEliminated() || mtd.isMain() || mtd.getMethodName().equals("__CLINIT__") || mtd.getMethodName().equals("finalize") || mtd.isNative()) {
                    if (!mtd.isEliminated() && mtd.getMethodName().contains("yield")) {
                        System.out.println("Not eliminating method ");
                        System.out.println("main="+mtd.isMain()+", isNative="+mtd.isNative());
                    }
                    continue;
                }

                if(!isMethodUsed(mtd, bc)) {
                    if(isMethodUsedByBaseClassOrInterface(mtd, bc)) {
                        continue;
                    }
                    mtd.setEliminated(true);
                    nfound++;
                }
            }

        }
        return nfound;
    }
    
    private static boolean isMethodUsedByBaseClassOrInterface(BytecodeMethod mtd, ByteCodeClass cls) {
        boolean b = checkMethodUsedByBaseClassOrInterface(mtd, cls.getBaseClassObject());
        if(b) {
            return true;
        }
        for(ByteCodeClass bc : cls.getBaseInterfacesObject()) {
            b = checkMethodUsedByBaseClassOrInterface(mtd, bc);
            if(b) {
                return true;
            }
        }
        return false;
    }

    private static boolean checkMethodUsedByBaseClassOrInterface(BytecodeMethod mtd, ByteCodeClass cls) {
        if(cls == null) {
            return false;
        }
        if(cls.getBaseInterfacesObject() != null) {
            for(ByteCodeClass bc : cls.getBaseInterfacesObject()) {
                for(BytecodeMethod m :  bc.getMethods()) {
                    if (m.isEliminated()) continue;
                    if(m.getMethodName().equals(mtd.getMethodName())) {
                        if (isMethodUsed(m, bc)) {
                            return true;
                        }
                        break;
                    }
                }
            }
        }
        for(BytecodeMethod m :  cls.getMethods()) {
            if (m.isEliminated()) continue;
            if(m.getMethodName().equals(mtd.getMethodName())) {
                if(isMethodUsed(m, cls)) {
                    return true;
                }
                break;
            }
        }
        return false;
    }

    private static int cullClasses(boolean found, int depth) {
        System.out.println("cullClasses()");
        if(found && depth < 4) {
            for(ByteCodeClass bc : classes) {
                bc.updateAllDependencies();
            }   

            ByteCodeClass.markDependencies(classes, nativeSources);
            List tmp = ByteCodeClass.clearUnmarked(classes);
            /*if(ByteCodeTranslator.verbose) {
            System.out.println("Classes removed from: " + classCount + " to " + classes.size());
            for(ByteCodeClass bc : classes) {
            if(!tmp.contains(bc)) {
            System.out.println("Removed class: " + bc.getClsName());
            }
            }
            }*/

            // 2nd pass to mark classes as eliminated so that we can propagate down to each
            // method of the class to mark it eliminated so that virtual methods
            // aren't included later on when writing virtual methods
            Set removedClasses = new HashSet(classes);
            removedClasses.removeAll(tmp);
            int nfound = 0;
            for (ByteCodeClass cls : removedClasses) {
                nfound += cls.setEliminated(true);
            }
            classes = tmp;
            return nfound + eliminateUnusedMethods(nfound > 0, depth + 1);
        }

        // Note: We may still have a lot of classes that are kept around solely because
        // they implement an interface that is used.
        // We should try to remove such classes
        return 0;
    }
    

    
    private static boolean isMethodUsed(BytecodeMethod m, ByteCodeClass cls) {
        if (!m.isEliminated() && m.isMethodUsedByNative(nativeSources, cls)) {
            return true;
        }
        for(ByteCodeClass bc : classes) {
            for(BytecodeMethod mtd : bc.getMethods()) {
                if(mtd.isEliminated() || mtd == m) {
                    continue;
                }
                if(mtd.isMethodUsed(m)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static void writeFile(ByteCodeClass cls, File outputDir, ConcatenatingFileOutputStream writeBufferInstead) throws Exception {
        OutputStream outMain =
                writeBufferInstead != null && ByteCodeTranslator.output == ByteCodeTranslator.OutputType.OUTPUT_TYPE_IOS ?
                        writeBufferInstead :
                        new FileOutputStream(new File(outputDir, cls.getClsName() + "." + ByteCodeTranslator.output.extension()));

        if (outMain instanceof ConcatenatingFileOutputStream) {
            ((ConcatenatingFileOutputStream)outMain).beginNextFile(cls.getClsName());
        }
        if(ByteCodeTranslator.output == ByteCodeTranslator.OutputType.OUTPUT_TYPE_IOS) {
            outMain.write(cls.generateCCode(classes).getBytes());
            outMain.close();

            // we also need to write the header file for iOS
            String headerName = cls.getClsName() + ".h";
            FileOutputStream outHeader = new FileOutputStream(new File(outputDir, headerName));
            outHeader.write(cls.generateCHeader().getBytes());
            outHeader.close();
        } else {
            outMain.write(cls.generateCSharpCode().getBytes());
            outMain.close();        
        }
    }
    
    public Parser() {
        super(Opcodes.ASM5);
    }

    @Override
    public void visitEnd() {
        super.visitEnd(); 
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        BytecodeMethod mtd = new BytecodeMethod(clsName, access, name, desc, signature, exceptions);
        cls.addMethod(mtd);
        JSRInlinerAdapter a = new JSRInlinerAdapter(new MethodVisitorWrapper(super.visitMethod(access, name, desc, signature, exceptions), mtd), access, name, desc, signature, exceptions);
        return a; 
    }

    @Override
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        ByteCodeField fld = new ByteCodeField(clsName, access, name, desc, signature, value);
        cls.addField(fld);
        return new FieldVisitorWrapper(super.visitField(access, name, desc, signature, value));
    }

    @Override
    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        if(name.equals(cls.getOriginalClassName())) {
            cls.setIsAnonymous(innerName==null);
        }
        super.visitInnerClass(name, outerName, innerName, access); 
    }

    @Override
    public void visitAttribute(Attribute attr) {
        super.visitAttribute(attr); 
    }

    @Override
    public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
        return new AnnotationVisitorWrapper(super.visitTypeAnnotation(typeRef, typePath, desc, visible)); 
    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        return new AnnotationVisitorWrapper(super.visitAnnotation(desc, visible));
    }

    @Override
    public void visitOuterClass(String owner, String name, String desc) {
        super.visitOuterClass(owner, name, desc); 
    }

    @Override
    public void visitSource(String source, String debug) {
        cls.setSourceFile(source);
        super.visitSource(source, debug); 
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        cls.setBaseClass(superName);
        cls.setBaseInterfaces(interfaces);
        if((access & Opcodes.ACC_ABSTRACT) == Opcodes.ACC_ABSTRACT) {
            cls.setIsAbstract(true);
        }
        if((access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE) {
            cls.setIsInterface(true);
        }
        if((access & Opcodes.ACC_ANNOTATION) == Opcodes.ACC_ANNOTATION) {
            cls.setIsAnnotation(true);
        }
        if((access & Opcodes.ACC_SYNTHETIC) == Opcodes.ACC_SYNTHETIC) {
            cls.setIsSynthetic(true);
        }
        
        if((access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL) {
            cls.setFinalClass(true);
        }
        if ("com/codename1/testing/UnitTest".equals(superName) || "com/codename1/testing/AbstractTest".equals(superName)) {
            cls.setIsUnitTest(true);
        }
        if ((access & Opcodes.ACC_ENUM) == Opcodes.ACC_ENUM) {
            cls.setIsEnum(true);
        }
        super.visit(version, access, name, signature, superName, interfaces); 
    }    
    
    class MethodVisitorWrapper extends MethodVisitor {
        private BytecodeMethod mtd;
        public MethodVisitorWrapper(MethodVisitor mv, BytecodeMethod mtd) {
            super(Opcodes.ASM5, mv);
            this.mtd = mtd;
        }

        @Override
        public void visitEnd() {
            super.visitEnd(); 
        }

        @Override
        public void visitMaxs(int maxStack, int maxLocals) {
            mtd.setMaxes(maxStack, maxLocals);
            super.visitMaxs(maxStack, maxLocals); 
        }

        @Override
        public void visitLineNumber(int line, Label start) {
            mtd.addDebugInfo(line);
            super.visitLineNumber(line, start); 
        }

        @Override
        public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
            return new AnnotationVisitorWrapper(super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible));
        }

        @Override
        public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
            mtd.addLocalVariable(name, desc, signature, start, end, index);
            super.visitLocalVariable(name, desc, signature, start, end, index); 
        }

        @Override
        public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
            return new AnnotationVisitorWrapper(super.visitTryCatchAnnotation(typeRef, typePath, desc, visible));
        }

        @Override
        public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
            mtd.addTryCatchBlock(start, end, handler, type);
            super.visitTryCatchBlock(start, end, handler, type); 
        }

        @Override
        public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
            return new AnnotationVisitorWrapper(super.visitInsnAnnotation(typeRef, typePath, desc, visible)); 
        }

        @Override
        public void visitMultiANewArrayInsn(String desc, int dims) {
            mtd.addMultiArray(desc, dims);
            super.visitMultiANewArrayInsn(desc, dims); 
        }

        @Override
        public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
            mtd.addSwitch(dflt, keys, labels);
            super.visitLookupSwitchInsn(dflt, keys, labels); 
        }

        @Override
        public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
            int[] keys = new int[labels.length];
            int counter = min;
            for(int iter = 0 ; iter < keys.length ; iter++) {
                keys[iter] = counter;
                counter++;
            }
            mtd.addSwitch(dflt, keys, labels);
            super.visitTableSwitchInsn(min, max, dflt, labels); 
        }

        @Override
        public void visitIincInsn(int var, int increment) {
            mtd.addIInc(var, increment);
            super.visitIincInsn(var, increment); 
        }

        @Override
        public void visitLdcInsn(Object cst) {
            mtd.addLdc(cst);
            super.visitLdcInsn(cst); 
        }

        @Override
        public void visitLabel(Label label) {
            mtd.addLabel(label);
            super.visitLabel(label); 
        }

        @Override
        public void visitJumpInsn(int opcode, Label label) {
            mtd.addJump(opcode, label);
            super.visitJumpInsn(opcode, label); 
        }

        @Override
        public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
            super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); 
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
            mtd.addInvoke(opcode, owner, name, desc, itf);
            super.visitMethodInsn(opcode, owner, name, desc, itf); 
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            super.visitMethodInsn(opcode, owner, name, desc); 
        }

        @Override
        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
            mtd.addField(cls, opcode, owner, name, desc);
            super.visitFieldInsn(opcode, owner, name, desc); 
        }

        @Override
        public void visitTypeInsn(int opcode, String type) {
            mtd.addTypeInstruction(opcode, type);
            super.visitTypeInsn(opcode, type); 
        }

        @Override
        public void visitVarInsn(int opcode, int var) {
            mtd.addVariableOperation(opcode, var);
            super.visitVarInsn(opcode, var); 
        }

        @Override
        public void visitIntInsn(int opcode, int operand) {
            mtd.addVariableOperation(opcode, operand);
            super.visitIntInsn(opcode, operand); 
        }

        @Override
        public void visitInsn(int opcode) {
            mtd.addInstruction(opcode);
            super.visitInsn(opcode); 
        }

        @Override
        public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
            super.visitFrame(type, nLocal, local, nStack, stack); 
        }

        @Override
        public void visitCode() {
            super.visitCode(); 
        }

        @Override
        public void visitAttribute(Attribute attr) {
            super.visitAttribute(attr); 
        }

        @Override
        public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
            if (mv == null) return null;
            return new AnnotationVisitorWrapper(super.visitParameterAnnotation(parameter, desc, visible));
        }

        @Override
        public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
            if (mv == null) return null;
            return new AnnotationVisitorWrapper(super.visitTypeAnnotation(typeRef, typePath, desc, visible));
        }

        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            if (mv == null) return null;
            return new AnnotationVisitorWrapper(super.visitAnnotation(desc, visible)); 
        }

        @Override
        public AnnotationVisitor visitAnnotationDefault() {
            if (mv == null) return null;
            return new AnnotationVisitorWrapper(super.visitAnnotationDefault());
        }

        @Override
        public void visitParameter(String name, int access) {
            super.visitParameter(name, access); 
        }    
        
        
    }
    
    class FieldVisitorWrapper extends FieldVisitor {

        public FieldVisitorWrapper(FieldVisitor fv) {
            super(Opcodes.ASM5, fv);
        }

        @Override
        public void visitEnd() {
            super.visitEnd(); 
        }

        @Override
        public void visitAttribute(Attribute attr) {
            super.visitAttribute(attr); 
        }

        @Override
        public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
            return super.visitTypeAnnotation(typeRef, typePath, desc, visible); 
        }

        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            return super.visitAnnotation(desc, visible); 
        }
        
    }
    
    class AnnotationVisitorWrapper extends AnnotationVisitor {

        public AnnotationVisitorWrapper(AnnotationVisitor av) {
            super(Opcodes.ASM5, av);
        }

        @Override
        public void visitEnd() {
            super.visitEnd(); 
        }

        @Override
        public AnnotationVisitor visitArray(String name) {
            if (av == null) return null;
            return super.visitArray(name); 
        }

        @Override
        public AnnotationVisitor visitAnnotation(String name, String desc) {
            if (av == null) return null;
            return super.visitAnnotation(name, desc); 
        }

        @Override
        public void visitEnum(String name, String desc, String value) {
            super.visitEnum(name, desc, value); 
        }

        @Override
        public void visit(String name, Object value) {
            super.visit(name, value); 
        }
        
        
    
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy