Package kilim.analysis

Source Code of kilim.analysis.ClassWeaver

/* Copyright (c) 2006, Sriram Srinivasan
*
* You may distribute this software under the terms of the license
* specified in the file "License"
*/

package kilim.analysis;
import kilim.*;
import static kilim.Constants.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InnerClassNode;

/**
* This class is the main entry point for the Weave tool. It uses
* ClassFlow to parse and analyze a class file, and writes out a
* CPS transformed file if needed
*/
public class ClassWeaver {
    ClassFlow       classFlow;
    List<ClassInfo> classInfoList = new LinkedList<ClassInfo>();
   
    static ThreadLocal<HashSet<String>> stateClasses = new ThreadLocal<HashSet<String>>() {
      protected java.util.HashSet<String> initialValue() {
        return new HashSet<String>();
      }
    };

    public static void reset() {
      stateClasses.set(new HashSet<String>());
    }

    public ClassWeaver(byte[] data, Detector detector) {
        classFlow = new ClassFlow(data, detector);
        weave();
    }
   
    public ClassWeaver(InputStream is, Detector detector) throws IOException {
        classFlow = new ClassFlow(is, detector);
        weave();
    }
   
    public ClassWeaver(String className, Detector detector) throws IOException {
        classFlow = new ClassFlow(className, detector);
        weave();
    }
   
    private void weave() throws KilimException {
        classFlow.analyze(false);
        if (classFlow.isPausable() && needsWeaving()) {
            ClassWriter cw = new ClassWriter(false);
            accept(cw);
            addClassInfo(new ClassInfo(classFlow.getClassName(), cw.toByteArray()));
        }
    }

    private void accept(final ClassVisitor cv) {
        ClassFlow cf = classFlow;
        // visits header
        String[] interfaces = toStringArray(cf.interfaces);
        cv.visit(cf.version, cf.access, cf.name, cf.signature, cf.superName, interfaces);
        // visits source
        if (cf.sourceFile != null || cf.sourceDebug != null) {
            cv.visitSource(cf.sourceFile, cf.sourceDebug);
        }
        // visits outer class
        if (cf.outerClass != null) {
            cv.visitOuterClass(cf.outerClass, cf.outerMethod, cf.outerMethodDesc);
        }
        // visits attributes and annotations
        int i, n;
        AnnotationNode an;
        n = cf.visibleAnnotations == null ? 0 : cf.visibleAnnotations.size();
        for (i = 0; i < n; ++i) {
            an = (AnnotationNode) cf.visibleAnnotations.get(i);
            an.accept(cv.visitAnnotation(an.desc, true));
        }
        n = cf.invisibleAnnotations == null ? 0
                : cf.invisibleAnnotations.size();
        for (i = 0; i < n; ++i) {
            an = (AnnotationNode) cf.invisibleAnnotations.get(i);
            an.accept(cv.visitAnnotation(an.desc, false));
        }
       
        n = cf.attrs == null ? 0 : cf.attrs.size();
        for (i = 0; i < n; ++i) {
            cv.visitAttribute((Attribute) cf.attrs.get(i));
        }
        // visits inner classes
        for (i = 0; i < cf.innerClasses.size(); ++i) {
            ((InnerClassNode) cf.innerClasses.get(i)).accept(cv);
        }
        // visits fields
        for (i = 0; i < cf.fields.size(); ++i) {
            ((FieldNode) cf.fields.get(i)).accept(cv);
        }
        /*
         * Mark this class as "processed" by adding a dummy field, so that
         * we don't weave an already woven file
         */
        cv.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, WOVEN_FIELD, "Z", "Z", Boolean.TRUE);
        // visits methods
        for (i = 0; i < cf.methods.size(); ++i) {
            MethodFlow m = (MethodFlow) cf.methods.get(i);
            if (needsWeaving(m)) {
                MethodWeaver mw = new MethodWeaver(this, m);
                mw.accept(cv);
                mw.makeNotWovenMethod(cv, m);
            } else {
                m.accept(cv);
            }
        }
        // visits end
        cv.visitEnd();
    }

    @SuppressWarnings(value = { "unchecked" })
    static String[] toStringArray(List list) {
        String[] array = new String[list.size()];
        list.toArray(array);
        return array;
    }

    void addClassInfo(ClassInfo ci) {
        classInfoList.add(ci);
    }
   
    public List<ClassInfo>  getClassInfos() {
        return classInfoList;
    }
   
    /*
     * A method needs weaving ordinarily if it is marked pausable.
     * However, if there exists another method with the same name
     * and parameters and an additional Fiber parameter as the last
     * one, then this method doesn't need weaving. Examples are
     * kilim.Task.yield and kilim.Task.sleep
     */
    static String FIBER_SUFFIX = D_FIBER + ')';
    boolean needsWeaving(MethodFlow mf) {
        if (!mf.isPausable() || mf.desc.endsWith(FIBER_SUFFIX))
            return false;
        String fdesc = mf.desc.replace(")", FIBER_SUFFIX);
        for (MethodFlow omf: classFlow.getMethodFlows()) {
            if (omf == mf) continue;
            if (mf.name.equals(omf.name) && fdesc.equals(omf.desc)) {
                return false;
            }
        }
        return true;
    }
   
    boolean needsWeaving() {
        if (classFlow.isWoven) return false;
        for (MethodFlow mf: classFlow.getMethodFlows()) {
            if (needsWeaving(mf)) return true;
        }
        return false;
    }
   
    /**
     * Create a custom class (structure) to hold the state. The name of the
     * state reflects the numbers of the various VMtypes in valInfoList. class
     * kilim.SO2IJ3 reflects a class that stores two Objects one Integer and 3
     * longs.
     *
     * <pre>
     *            class kilim.SO2IJ3 extends kilim.State {
     *               public Object f1, f2;
     *               public int f3;
     *               public long f4, f5, f6;
     *            }
     * </pre>
     *
     * If there's no data to store, we use the kilim.State class directly to
     * store the basic amount of data necessary to restore the stack.
     */

    String createStateClass(ValInfoList valInfoList) {
        int numByType[] = { 0, 0, 0, 0, 0 };
        for (ValInfo vi : valInfoList) {
            numByType[vi.vmt]++;
        }
        String className = makeClassName(numByType);
        HashSet<String> classes = stateClasses.get();
    if (classes.contains(className)) {
            return className;
        }
        classes.add(className);
        ClassWriter cw = new ClassWriter(false);
        cw.visit(V1_1, ACC_PUBLIC | ACC_FINAL, className, null, "kilim/State", null);

        // Create default constructor
        // <init>() {
        // super(); // call java/lang/Object.<init>()
        // }
        MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mw.visitInsn(ALOAD_0);
        mw.visitMethodInsn(INVOKESPECIAL, STATE_CLASS, "<init>", "()V");
        mw.visitInsn(RETURN);
        // this code uses a maximum of one stack element and one local variable
        mw.visitMaxs(1, 1);
        mw.visitEnd();
        // create fields of the appropriate type.
        for (ValInfo vi : valInfoList) {
            cw.visitField(ACC_PUBLIC, vi.fieldName, vi.fieldDesc(), null, null);
        }
        addClassInfo(new ClassInfo(className, cw.toByteArray()));
        return className;
    }

    private String makeClassName(int[] numByType) {
        StringBuilder sb = new StringBuilder(30);
        sb.append("kilim/S_");
        for (int t = 0; t < 5; t++) {
            int c = numByType[t];
            if (c == 0)
                continue;
            sb.append(VMType.abbrev[t]);
            if (c > 1) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    boolean isInterface() {
        return classFlow.isInterface();
    }
}

TOP

Related Classes of kilim.analysis.ClassWeaver

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.