Package alt.jiapi.interceptor

Source Code of alt.jiapi.interceptor.FieldAdvisorInstrumentor

package alt.jiapi.interceptor;

import java.util.List;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import alt.jiapi.InstrumentationException;

import alt.jiapi.event.EventInstrumentor;
import alt.jiapi.event.EventRuntime;

import alt.jiapi.reflect.Instruction;
import alt.jiapi.reflect.InstructionFactory;
import alt.jiapi.reflect.InstructionList;
import alt.jiapi.reflect.JiapiClass;
import alt.jiapi.reflect.JiapiField;
import alt.jiapi.reflect.JiapiMethod;
import alt.jiapi.reflect.Loader;
import alt.jiapi.reflect.Signature;
import alt.jiapi.reflect.SignatureUtil;

import alt.jiapi.reflect.FieldExistsException;
import alt.jiapi.reflect.MethodExistsException;

import alt.jiapi.reflect.instruction.FieldAccess;
import alt.jiapi.reflect.instruction.Invocation;
import alt.jiapi.reflect.instruction.OpcodeGroups;
import alt.jiapi.reflect.instruction.Opcodes;

import alt.jiapi.util.HotSpot;
import alt.jiapi.util.HotSpotLocator;


/**
* Class FieldInstrumentor.
*
* @author Mika Riekkinen
*/
class FieldAdvisorInstrumentor extends EventInstrumentor {
    private AccessAdvisor advisor;
    private JiapiMethod getMethod;
    private JiapiMethod setMethod;

    FieldAdvisorInstrumentor(FieldInterceptor fi, AccessAdvisor advisor) {
        super(fi);
        this.advisor = advisor;

        JiapiClass jc = getEventProducer();
        try {
            this.getMethod =
                jc.getDeclaredMethod("getField",
                                     new String[] { "java.lang.Object",
                                                    "java.lang.String",
                                                    "java.lang.Object"});

            this.setMethod =
                jc.getDeclaredMethod("setField",
                                     new String[] { "java.lang.Object",
                                                    "java.lang.String",
                                                    "java.lang.Object"});
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public void instrument(JiapiMethod jm) {
        JiapiClass clazz = jm.getDeclaringClass();
        JiapiField interceptor = getEventProducerField();
        InstructionList il = jm.getInstructionList();
        InstructionFactory factory = il.getInstructionFactory();

        HotSpotLocator hsl =
            new HotSpotLocator(il, new byte[]{Opcodes.GETSTATIC,
                                              Opcodes.GETFIELD});
        HotSpot[] hotSpots = hsl.getHotSpots();

        for (int i = 0; i < hotSpots.length; i++) {
            FieldAccess fa = (FieldAccess)hotSpots[i].getHotSpotInstruction();
            short opCode = fa.getOpcode();

            if (!match(fa.getClassName() + "." + fa.getFieldName())) {
                continue;
            }

            InstructionList hsList = hotSpots[i].getInstructionList();
            InstructionList nList = il.createEmptyList();

            boolean primitive = SignatureUtil.isPrimitive(fa.getTypeName());


            if (opCode == Opcodes.GETSTATIC ||
                opCode == Opcodes.GETFIELD) {
                nList.add(factory.getField(interceptor)); // Interceptor

                // NOTE: We could store Class into variable,
                //       and use getField() instead of Class.forName() call
                // Class or objref; 1st parameter to interceptor
                if (opCode == Opcodes.GETSTATIC) {
                    short lvIdx =
                        addClassForNameInstructions(fa.getClassName(), jm);
                    nList.add(factory.aload(lvIdx));
//                     addClassForNameInstructions(fa.getClassName(), nList);
//                     nList.add(factory.pushNull());
                }
                else {
                    //addClassForNameInstructions(fa.getClassName(), nList);
                    nList.add(hsList.get(0)); // objref
                }

                // Name of the field; 2nd parameter to interceptor
                nList.add(factory.pushConstant(fa.getFieldName()));

                // 3rd parameter; field value
                Instruction pIns = null;
                if (primitive) {
                    // Provide wrapper for primitive types
                    pIns = handlePrimitiveType(fa.getTypeName(), nList);
                }
                //nList.add(fa);
                //nList.add(hsList);
                nList.add(hotSpots[i].getInstructionList());

                if (pIns != null) {
                    nList.add(pIns);
                }

                // call Interceptor
                nList.add(factory.invoke(getMethod));

                handleReturnValue(nList, fa.getTypeName());
                //nList.add(factory.cast(fa.getTypeName()));

                hotSpots[i].getInstructionList()/* hsList*/.replace(nList);
            }
        }
    }


    /**
     * Add Class.forName(name) instructions in fhe beginning of method.
     * Class is stored in next available local-variable
     * We could also store this into class-variable, and initialize
     * values in <clinit>
     *
     * @return index of the local variable, where Class is stored
     */
    private short addClassForNameInstructions(String name, JiapiMethod jm) {
        InstructionList il = jm.getInstructionList();
        InstructionFactory f = il.getInstructionFactory();

        InstructionList nl = il.createEmptyList();
        short maxLocals = (short)jm.getMaxLocals();
       
        // NOTE: We do not create exception handlers for
        //       Class.forName(...) invocation.
        //       However, we use this to get Class of the running object,
        //       so its Class is allways found.
        try {
            nl.add(f.pushConstant(name));
            nl.add(f.invoke(Modifier.STATIC, "java.lang.Class",
                            "forName", new Signature("java.lang.Class",
                                                     new String[] {"java.lang.String"})));
            nl.add(f.astore(maxLocals));
        }
        catch(Exception e) {
            e.printStackTrace();
            il.add(f.pushNull());
        }

//         il.add(nl);
        il.insert(0, nl);

        return maxLocals;
    }


    private boolean isPublicField(FieldAccess fa) {
        try {
            JiapiClass jc = new Loader().loadClass(fa.getClassName());
            JiapiField jf = jc.getField(fa.getName());

            return Modifier.isPublic(jf.getModifiers());
        }
        catch(Exception e) {
            e.printStackTrace();
        }

        return false;
    }



    private void handleReturnValue(InstructionList il, String rType) {
        // Convert return value if needed.
        InstructionFactory factory = il.getInstructionFactory();

        if ("int".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Integer");
                JiapiMethod jm =
                    jc.getDeclaredMethod("intValue", new String[0]);

                il.add(factory.cast("java.lang.Integer"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("long".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Long");
                JiapiMethod jm =
                    jc.getDeclaredMethod("longValue", new String[0]);

                il.add(factory.cast("java.lang.Long"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("char".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Character");
                JiapiMethod jm =
                    jc.getDeclaredMethod("charValue", new String[0]);

                il.add(factory.cast("java.lang.Character"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("boolean".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Boolean");
                JiapiMethod jm =
                    jc.getDeclaredMethod("booleanValue", new String[0]);

                il.add(factory.cast("java.lang.Boolean"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("byte".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Byte");
                JiapiMethod jm =
                    jc.getDeclaredMethod("byteValue", new String[0]);

                il.add(factory.cast("java.lang.Byte"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("float".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Float");
                JiapiMethod jm =
                    jc.getDeclaredMethod("floatValue", new String[0]);

                il.add(factory.cast("java.lang.Float"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("double".equals(rType)) {
            try {
                JiapiClass jc = new Loader().loadClass("java.lang.Double");
                JiapiMethod jm =
                    jc.getDeclaredMethod("doubleValue", new String[0]);

                il.add(factory.cast("java.lang.Double"));
                il.add(factory.invoke(jm));
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else if ("void".equals(rType)){
            // Pop out the return value(probably null) of
            // the invocation handler if it was a 'void' method
            il.add(new Instruction(new byte[]{Opcodes.POP}));
        }
        else { // Cast to correct Object
            il.add(factory.cast(rType));
        }
    }



    /**
     * @return an Invocation to constructor of primitive wrapper
     */
    private Instruction handlePrimitiveType(String type, InstructionList il) {
        InstructionFactory f = il.getInstructionFactory();
        String cName = null;
        Signature s = new Signature("void", new String[]{ type });

        if ("int".equals(type)) {
            cName = "java.lang.Integer";
        }
        else if ("long".equals(type)) {
            cName = "java.lang.Long";
        }
        else if ("char".equals(type)) {
            cName = "java.lang.Character";
        }
        else if ("boolean".equals(type)) {
            cName = "java.lang.Boolean";
        }
        else if ("byte".equals(type)) {
            cName = "java.lang.Byte";
        }
        else if ("float".equals(type)) {
            cName = "java.lang.Float";
        }
        else if ("double".equals(type)) {
            cName = "java.lang.Double";
        }

         il.add(f.newClass(cName));
         il.add(f.dup());
         Instruction ins = f.invoke(Modifier.PUBLIC, cName, "<init>", s);
         return ins;
    }
}
TOP

Related Classes of alt.jiapi.interceptor.FieldAdvisorInstrumentor

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.