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 static kilim.Constants.D_FIBER;
import static kilim.Constants.STATE_CLASS;
import static kilim.Constants.WOVEN_FIELD;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V1_1;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import kilim.KilimException;
import kilim.mirrors.Detector;

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 {
    public ClassFlow classFlow;
    List<ClassInfo> classInfoList = new LinkedList<ClassInfo>();
    static ThreadLocal<HashMap<String, ClassInfo>> stateClasses_ =
        new ThreadLocal<HashMap<String, ClassInfo>>() {
      protected HashMap<String, ClassInfo> initialValue() {
        return new HashMap<String, ClassInfo>();
      }
    };
   
    public static void reset() {
      stateClasses_.set(new HashMap<String, ClassInfo>() );
    }
   
    private final ClassLoader classLoader;
   
    public ClassWeaver(byte[] data) {
        this(data, Detector.DEFAULT, Thread.currentThread().getContextClassLoader());
    }
   
    public ClassWeaver(byte[] data, Detector detector) {
      this(data, detector, Thread.currentThread().getContextClassLoader());
    }
   
    public ClassWeaver(InputStream is, Detector detector) throws IOException {
      this(is, detector, Thread.currentThread().getContextClassLoader());
    }
   
    public ClassWeaver(String className, Detector detector) throws IOException {
        this(className, detector, Thread.currentThread().getContextClassLoader());
    }
   
    public ClassWeaver(byte[] data, Detector detector, ClassLoader classLoader) {
        classFlow = new ClassFlow(data, detector);
        this.classLoader = classLoader;
    }
   
    public ClassWeaver(InputStream is, Detector detector, ClassLoader classLoader) throws IOException {
        classFlow = new ClassFlow(is, detector);
        this.classLoader = classLoader;
    }
   
    public ClassWeaver(String className, Detector detector, ClassLoader classLoader) throws IOException {
        classFlow = new ClassFlow(className, detector);
        this.classLoader = classLoader;
    }
   
    public void weave() throws KilimException {
        classFlow.analyze(false);
        if (needsWeaving() && classFlow.isPausable()) {
            boolean computeFrames = (classFlow.version & 0x00FF) >= 50;
            ClassWriter cw = new kilim.analysis.ClassWriter(computeFrames ? ClassWriter.COMPUTE_FRAMES : 0, classFlow.detector());
            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.restoreNonInstructionNodes();
                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);
        ClassInfo classInfo= null;
            classInfo= stateClasses_.get().get(className);
            if (classInfo == null) {
                ClassWriter cw = new kilim.analysis.ClassWriter(ClassWriter.COMPUTE_FRAMES, classFlow.detector());
                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.visitVarInsn(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);
                }
                classInfo= new ClassInfo(className, cw.toByteArray());
                stateClasses_.get().put(className, classInfo);
            }
        if (!classInfoList.contains(classInfo))
          addClassInfo(classInfo);
        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.