ClassEnhancer.java :  » Testing » PolePosition-0.20 » com » versant » core » jdo » tools » enhancer » Java Open Source

Java Open Source » Testing » PolePosition 0.20 
PolePosition 0.20 » com » versant » core » jdo » tools » enhancer » ClassEnhancer.java

/*
 * Copyright (c) 1998 - 2005 Versant Corporation
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Versant Corporation - initial API and implementation
 */
package com.versant.core.jdo.tools.enhancer;

import com.versant.lib.bcel.Constants;
import com.versant.lib.bcel.classfile.*;
import com.versant.lib.bcel.generic.*;
import com.versant.core.common.Debug;
import com.versant.core.jdo.tools.enhancer.info.ClassInfo;
import com.versant.core.jdo.tools.enhancer.info.FieldInfo;
import com.versant.core.jdo.tools.enhancer.utils.SerialUIDHelper;
import com.versant.core.jdo.tools.enhancer.utils.SwapFieldHelper;
import com.versant.core.jdo.tools.enhancer.utils.TableSwitchHelper;
import com.versant.core.metadata.ClassMetaData;
import com.versant.core.metadata.MDStatics;

import javax.jdo.JDOUserException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.net.URL;

/**
 * This class does the enhancement on class files
 *
 */
public class ClassEnhancer {


    private ClassGen classGen;
    private ConstantPoolGen constantPoolGen;
    private InstructionFactory instructionFactory;
    private ClassInfo classInfo;
    private Set fieldSet;
    private File outputDir;
    private ClassLoader loader;
    private static int javaVersion;

    private boolean isEmpty = false;
    private boolean didWeAddADefaultConstructor = false;

    public static final int JAVA_1_0 = 10;
    public static final int JAVA_1_1 = 11;
    public static final int JAVA_1_2 = 12;
    public static final int JAVA_1_3 = 13;
    public static final int JAVA_1_4 = 14;
    public static final int JAVA_1_5 = 15;

    private static final String getField = com.versant.lib.bcel.generic.GETFIELD.class.getName();
    private static final String putField = com.versant.lib.bcel.generic.PUTFIELD.class.getName();
    private static final String invokeSpecial = com.versant.lib.bcel.generic.INVOKESPECIAL.class.getName();
    private static final String aload = com.versant.lib.bcel.generic.ALOAD.class.getName();
    private static final String dup = com.versant.lib.bcel.generic.DUP.class.getName();


    private HashMap getAndSettersMap;
    private HashMap typeToReturnType;
    private HashMap typeToSetField;
    private HashMap typeToFieldProvider;
    private HashMap typeToProvidedField;
    private HashMap typeToReplacingField;
    private HashMap typeToGetField;
    private HashMap typeToLoadType;
    private HashMap typeToFieldReplacer;

    private HashMap primativeTypesToWrapper;

    private String fileSeparator;
  private char charfileSeparator;         //
    private static final String VERSANT_STATE_MANAGER = com.versant.core.jdo.VersantStateManager.class.getName();

    private final static String PERSISTENCE_CAPABLE = javax.jdo.spi.PersistenceCapable.class.getName();
    private final static ObjectType PC_OBJECT_TYPE = new ObjectType(PERSISTENCE_CAPABLE);
    private final static String STATE_MANAGER = javax.jdo.spi.StateManager.class.getName();
    private final static ObjectType SM_OBJECT_TYPE = new ObjectType(STATE_MANAGER);
    private int CHECK_WRITE = javax.jdo.spi.PersistenceCapable.CHECK_WRITE;
    private int CHECK_READ_WRITE = javax.jdo.spi.PersistenceCapable.CHECK_READ + javax.jdo.spi.PersistenceCapable.CHECK_WRITE;
    private int MEDIATE_READ_WRITE = javax.jdo.spi.PersistenceCapable.MEDIATE_READ + javax.jdo.spi.PersistenceCapable.MEDIATE_WRITE;
    private int synthetic;
  private String vendorName = "jdoVersant";

    private long currentSerialVersionUID;
    private static final String DIRTY_FIELD_NAME = "jdoVersantDirty";
    private static final String LOADED_FIELD_NAME = "jdoVersantLoaded";
    private static final String OID_FIELD_NAME = "jdoVersantOID";
    private static final String VERSION_FIELD_NAME = "jdoVersantVersion";
    private static final String DETACHABLE_INTERFASE = com.versant.core.jdo.VersantDetachable.class.getName();
    private static final String DETACHED_STATE_MANAGER = com.versant.core.jdo.VersantDetachedStateManager.class.getName();
    private int totlalManagedFields = 0;
    private boolean detach;
    private File currentOutputFile;

    public static final ObjectType INTEGER_TYPE = new ObjectType(
            "java.lang.Integer");
    public static final ObjectType BYTE_TYPE = new ObjectType("java.lang.Byte");
    public static final ObjectType CHARACTER_TYPE = new ObjectType(
            "java.lang.Character");
    public static final ObjectType SHORT_TYPE = new ObjectType(
            "java.lang.Short");
    public static final ObjectType FLOAT_TYPE = new ObjectType(
            "java.lang.Float");
    public static final ObjectType DOUBLE_TYPE = new ObjectType(
            "java.lang.Double");
    public static final ObjectType LONG_TYPE = new ObjectType("java.lang.Long");
    public static final ObjectType BOOLEAN_TYPE = new ObjectType(
            "java.lang.Boolean");

//  private static final String MAKE_HOLLOW_INTERFASE = com.versant.core.jdo.test.model.versantMakeHollow.class.getName();

    static {

        // Determine the Java version by looking at available classes
        // java.lang.StrictMath was introduced in JDK 1.3
        // java.lang.ThreadLocal was introduced in JDK 1.2
        // java.lang.Void was introduced in JDK 1.1
        // Count up version until a NoClassDefFoundError ends the try

        try {
            javaVersion = JAVA_1_0;
            Class.forName("java.lang.Void");
            javaVersion = JAVA_1_1;
            Class.forName("java.lang.ThreadLocal");
            javaVersion = JAVA_1_2;
            Class.forName("java.lang.StrictMath");
            javaVersion = JAVA_1_3;
            Class.forName("java.lang.CharSequence");
            javaVersion = JAVA_1_4;
//            Class.forName("java.lang.StringBuilder");
//            javaVersion = JAVA_1_5;
        } catch (ClassNotFoundException cnfe) {
            // swallow as we've hit the max class version that
            // we have
        }
    }

    public ClassEnhancer(File outputDir, ClassLoader loader) {
        this.outputDir = outputDir;
        this.loader = loader;
        fileSeparator = System.getProperty("file.separator");
    charfileSeparator = fileSeparator.charAt(0);

        typeToSetField = new HashMap();
        typeToSetField.put(Type.INT,    "setIntField");
        typeToSetField.put(Type.BYTE,   "setByteField");
        typeToSetField.put(Type.LONG,   "setLongField");
        typeToSetField.put(Type.CHAR,   "setCharField");
        typeToSetField.put(Type.SHORT,  "setShortField");
        typeToSetField.put(Type.FLOAT,  "setFloatField");
        typeToSetField.put(Type.DOUBLE, "setDoubleField");
        typeToSetField.put(Type.STRING, "setStringField");
        typeToSetField.put(Type.BOOLEAN,"setBooleanField");

        typeToFieldProvider = new HashMap();
        typeToFieldProvider.put(Type.INT,    "fetchIntField");
        typeToFieldProvider.put(Type.BYTE,   "fetchByteField");
        typeToFieldProvider.put(Type.CHAR,   "fetchCharField");
        typeToFieldProvider.put(Type.SHORT,  "fetchShortField");
        typeToFieldProvider.put(Type.FLOAT,  "fetchFloatField");
        typeToFieldProvider.put(Type.DOUBLE, "fetchDoubleField");
        typeToFieldProvider.put(Type.LONG,   "fetchLongField");
        typeToFieldProvider.put(Type.BOOLEAN,"fetchBooleanField");
        typeToFieldProvider.put(Type.STRING, "fetchStringField");

        typeToProvidedField = new HashMap();
        typeToProvidedField.put(Type.INT,   "providedIntField");
        typeToProvidedField.put(Type.BYTE,  "providedByteField");
        typeToProvidedField.put(Type.CHAR,  "providedCharField");
        typeToProvidedField.put(Type.SHORT, "providedShortField");
        typeToProvidedField.put(Type.FLOAT, "providedFloatField");
        typeToProvidedField.put(Type.DOUBLE,"providedDoubleField");
        typeToProvidedField.put(Type.LONG,  "providedLongField");
        typeToProvidedField.put(Type.BOOLEAN,"providedBooleanField");
        typeToProvidedField.put(Type.STRING,"providedStringField");

        typeToReplacingField = new HashMap();
        typeToReplacingField.put(Type.INT,      "replacingIntField");
        typeToReplacingField.put(Type.BYTE,     "replacingByteField");
        typeToReplacingField.put(Type.CHAR,     "replacingCharField");
        typeToReplacingField.put(Type.SHORT,    "replacingShortField");
        typeToReplacingField.put(Type.FLOAT,    "replacingFloatField");
        typeToReplacingField.put(Type.DOUBLE,   "replacingDoubleField");
        typeToReplacingField.put(Type.LONG,     "replacingLongField");
        typeToReplacingField.put(Type.BOOLEAN,  "replacingBooleanField");
        typeToReplacingField.put(Type.STRING,   "replacingStringField");

        typeToFieldReplacer = new HashMap();
        typeToFieldReplacer.put(Type.INT,      "storeIntField");
        typeToFieldReplacer.put(Type.BYTE,     "storeByteField");
        typeToFieldReplacer.put(Type.CHAR,     "storeCharField");
        typeToFieldReplacer.put(Type.SHORT,    "storeShortField");
        typeToFieldReplacer.put(Type.FLOAT,    "storeFloatField");
        typeToFieldReplacer.put(Type.DOUBLE,   "storeDoubleField");
        typeToFieldReplacer.put(Type.LONG,     "storeLongField");
        typeToFieldReplacer.put(Type.BOOLEAN,  "storeBooleanField");
        typeToFieldReplacer.put(Type.STRING,   "storeStringField");

        typeToGetField = new HashMap();
        typeToGetField.put(Type.INT,    "getIntField");
        typeToGetField.put(Type.BYTE,   "getByteField");
        typeToGetField.put(Type.CHAR,   "getCharField");
        typeToGetField.put(Type.SHORT,  "getShortField");
        typeToGetField.put(Type.FLOAT,  "getFloatField");
        typeToGetField.put(Type.DOUBLE, "getDoubleField");
        typeToGetField.put(Type.LONG,   "getLongField");
        typeToGetField.put(Type.BOOLEAN,"getBooleanField");
        typeToGetField.put(Type.STRING, "getStringField");

        typeToReturnType = new HashMap();
        typeToReturnType.put(Type.INT,      new IRETURN());
        typeToReturnType.put(Type.BYTE,     new IRETURN());
        typeToReturnType.put(Type.CHAR,     new IRETURN());
        typeToReturnType.put(Type.SHORT,    new IRETURN());
        typeToReturnType.put(Type.FLOAT,    new FRETURN());
        typeToReturnType.put(Type.DOUBLE,   new DRETURN());
        typeToReturnType.put(Type.LONG,     new LRETURN());
        typeToReturnType.put(Type.BOOLEAN,  new IRETURN());
        typeToReturnType.put(Type.STRING,   new ARETURN());

        typeToLoadType = new HashMap();
        typeToLoadType.put(Type.INT,      new ILOAD(1));
        typeToLoadType.put(Type.BYTE,     new ILOAD(1));
        typeToLoadType.put(Type.CHAR,     new ILOAD(1));
        typeToLoadType.put(Type.SHORT,    new ILOAD(1));
        typeToLoadType.put(Type.FLOAT,    new FLOAD(1));
        typeToLoadType.put(Type.DOUBLE,   new DLOAD(1));
        typeToLoadType.put(Type.LONG,     new LLOAD(1));
        typeToLoadType.put(Type.BOOLEAN,  new ILOAD(1));
        typeToLoadType.put(Type.STRING,   new ALOAD(1));


        primativeTypesToWrapper = new HashMap(8);
        primativeTypesToWrapper.put(Type.INT, INTEGER_TYPE);
        primativeTypesToWrapper.put(Type.BYTE, BYTE_TYPE);
        primativeTypesToWrapper.put(Type.CHAR, CHARACTER_TYPE);
        primativeTypesToWrapper.put(Type.SHORT, SHORT_TYPE);
        primativeTypesToWrapper.put(Type.FLOAT, FLOAT_TYPE);
        primativeTypesToWrapper.put(Type.DOUBLE, DOUBLE_TYPE);
        primativeTypesToWrapper.put(Type.LONG, LONG_TYPE);
        primativeTypesToWrapper.put(Type.BOOLEAN, BOOLEAN_TYPE);


    }



    public void setGetAndSettersMap(HashMap map){
        getAndSettersMap = map;
    }

    private JavaClass getJavaClass(String className)throws IOException{
        String classFileName = className.replace('.','/')+".class";
        InputStream inputStream = loader.getResourceAsStream(classFileName);
        if (inputStream == null){
          inputStream = loader.getResourceAsStream("/" + classFileName);
          if (inputStream == null){
            throw new javax.jdo.JDOFatalUserException(
                    "Class not found: " + className);
          }
        }
        ClassParser parser = new ClassParser(inputStream, classFileName);
        return parser.parse();
    }

    private JavaClass getOrigJavaClass(String className) throws IOException {
        String classFileName = className.replace('.', '/') + ".class";
        InputStream inputStream = loader.getResourceAsStream(classFileName);
        URL currentFileURL = loader.getResource(classFileName);
        if (currentFileURL.toString().startsWith("jar:") && outputDir == null){
            throw new javax.jdo.JDOFatalUserException("Can not write class "+ className +" into a jar. Please specify a output directory.");
        }
        currentOutputFile = new File(currentFileURL.getFile());
        if (inputStream == null) {
            inputStream = loader.getResourceAsStream("/" + classFileName);
            currentFileURL = loader.getResource("/" + classFileName);
            if (currentFileURL.toString().startsWith("jar:") && outputDir == null) {
                throw new javax.jdo.JDOFatalUserException("Can not write class " + className + " into a jar. Please specify a output directory.");
            }
            currentOutputFile = new File(currentFileURL.getFile());
            if (inputStream == null) {
                throw new javax.jdo.JDOFatalUserException("Class not found: " + className);
            }
        }
        ClassParser parser = new ClassParser(inputStream, classFileName);
        return parser.parse();
    }

    public boolean enhance(ClassInfo classInfo,ClassMetaData cmd, boolean makeFieldsPrivate, boolean detached){
        try{
            this.detach = detached;
            this.classInfo = classInfo;
            fieldSet = classInfo.getFieldList();
            if (fieldSet.isEmpty()){
                isEmpty = true;
            } else {
                isEmpty = false;
            }
            JavaClass javaClass = getOrigJavaClass(classInfo.getClassName());
            classGen = new ClassGen(javaClass);
            // ConstantPoolGen is used to represent the constant pool of a Classfile            ll
            constantPoolGen = classGen.getConstantPool();
            // used to create objects representing VM instructions
            instructionFactory = new InstructionFactory(constantPoolGen);

             if (implementsPC()){ //if the class already implements PC, don't enhance
                return false;
            }
            currentSerialVersionUID = SerialUIDHelper.computeSerialVersionUID(javaClass);
            synthetic = classGen.getConstantPool().addUtf8("Synthetic");


            boolean topClass = classInfo.getTopPCSuperClass() == null;
            boolean appIdentity = classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION;
            didWeAddADefaultConstructor = false;


            //Tasks
            rewriteStaticConstructor();
            setDefaultConstructor();
            setClass$();
            addSerialVersionUID();
            addJdoFieldNames();
            addJdoFieldFlags();
            if (topClass) addJdoStateManager();            //super
            if (topClass) addJdoFlags();                   //super
            addJdoInheritedFieldCount();
            addJdoPersistenceCapableSuperclass();
            addJdoFieldTypes();
            addJdoGetManagedFieldCount();
            if (topClass) addInterrogatives();             //super
            addFieldGetters();
            addFieldSetters();
            addJdoReplaceField();
            addJdoReplaceFields();               //super??????????????/
            addJdoProvideField();
            addJdoProvideFields();               //super??????????????/
            addJdoCopyFields();
            addJdoCopyField();
            if (topClass) addJdoPreSerialize();                //super
            addWriteObject();
            addReadObject();
            addRegisterClass();
            addJdoNewInstance1();
            addJdoNewInstance2();
            if (topClass || appIdentity) addJdoNewObjectIdInstance1();
            if (topClass || appIdentity) addJdoNewObjectIdInstance2();
            if (topClass) addJdoGetObjectId();                    //super
            if (topClass) addJdoGetTransactionalObjectId();       //super
            if (topClass) addJdoReplaceStateManager();            //super
            if (topClass) addJdoCopyKeyFieldsToObjectId1();
            if (topClass) addJdoCopyKeyFieldsToObjectId2();
            if (topClass) addJdoCopyKeyFieldsFromObjectId1();
            if (topClass) addJdoCopyKeyFieldsFromObjectId2();
            if (topClass) addJdoReplaceFlags();                   //super


            addJdoInterface();
            if (makeFieldsPrivate){
                setEnhancedFieldsPrivate();
            }
            swapGetterAndSetter();
            swapClone();

//          addVersantMakeHollow(); // put it in later
            totlalManagedFields = 0;
            if (detach){
                if (topClass){
                    ClassMetaData[] hier = cmd.pcHeirachy;
                    for (int i = 0; i < hier.length; i++) {
                        ClassMetaData classMetaData = hier[i];
                        totlalManagedFields += classMetaData.managedFields.length;
                    }
                    addFields();
                    addSetLoadedInt("versantSetLoaded");  //public void versantSetLoaded(int i);
                    addIsLoadedInt("versantIsLoaded"); //boolean versantIsLoaded(int i);
                    addIsDirty("versantIsDirty");   //boolean versantIsDirty();
                    addMakeDirtyInt("versantMakeDirty");
                    addIsDirtyInt("versantIsDirty");  //public boolean versantIsDirty(int fieldNo);
                    addSetOid("versantSetOID"); //public void versantSetOID(Object id);
                    addGetOid("versantGetOID"); //public Object versantGetOID();
                    addGetVersion("versantGetVersion"); //public Object versantGetVersion();
                    addSetVersion("versantSetVersion"); //public void versantSetVersion(Object version);
                    addGetStateManager("versantGetDetachedStateManager"); //StateManager versantGetDetachedStateManager();
                    addDetachInterfase();
                }
                addMakeDirtyString("versantMakeDirty"); //void versantMakeDirty(String s);// if the names change, change this method.
            }

            if (didWeAddADefaultConstructor) {
                isOurConstructorValid();
            }
            dumpClass();

            System.out.println("Persistence Capable = " + classInfo.getClassName());

        } catch (Exception e){
          e.printStackTrace();
            if (Debug.DEBUG) {
                Debug.ERR.println("Error in Enhancer");
                e.printStackTrace(Debug.ERR);
            }
        }
        return true;
    }

    private void isOurConstructorValid() {
        //this gets done only for the least-derived persistence capable class.
        if (classInfo.getPersistenceCapableSuperclass() != null) {
            return;
        }
        String superName = classGen.getSuperclassName();
        try {
            JavaClass javaClass = getJavaClass(superName);
            ClassGen classGen = new ClassGen(javaClass);
            Method[] methods = classGen.getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method m = methods[i];
                // native and abstract methods don't have any code
                // so continue with next method
                if (m.isNative() || m.isAbstract()) {
                    continue;
                }
                if (m.getName().equals("<init>")) {              //is constructor
                    if (m.getSignature().equals("()V")) {        //is no args constructor
                        if (!m.isPrivate()) {
                            return;
                        }
                    }
                }
            }
            throw new JDOUserException("Could not create a valid default constructor for class "+ this.classGen.getClassName());
        } catch (IOException e) {
            // hide exception, this class is not on our classpath
        }
    }

    private void addDefaultConstructorToNonPersistantSuperClasses(String superName) {
        //this gets done only for the least-derived persistence capable class.
        if (superName == null){
            if (classInfo.getPersistenceCapableSuperclass() != null) {
                return;
            }
            superName = classGen.getSuperclassName();
        }

        try {
            JavaClass javaClass = getJavaClass(superName);
            ClassGen classGen = new ClassGen(javaClass);
            // ConstantPoolGen is used to represent the constant pool of a Classfile            ll
            ConstantPoolGen constantPoolGen = classGen.getConstantPool();

            Method[] methods = classGen.getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method m = methods[i];
                // native and abstract methods don't have any code
                // so continue with next method
                if (m.isNative() || m.isAbstract()) {
                    continue;
                }

                if (m.getName().equals("<init>")) {              //is constructor
                    if (m.getSignature().equals("()V")) {        //is no args constructor
                        if (m.isPublic()) {
                            return;
                        } else {                                 //there is a default constructor but access is wrong
                            m.isPublic(true);
                            m.isProtected(false);                //change access to protected
                            m.isPrivate(false);                 //take away private access
                            String fileName = classGen.getClassName().replace('.', charfileSeparator) + ".class";
                            File dumpFile = new File(outputDir, fileName);
                            try {
                                classGen.getJavaClass().dump(dumpFile);
                            } catch (IOException e) {
                                //hide, we could not write out the class
                            }
                            return;
                        }
                    }
                }
            }

            InstructionList il = new InstructionList();
            il.append(InstructionConstants.THIS); // Push `this'
            il.append(new INVOKESPECIAL(constantPoolGen.addMethodref(classGen.getSuperclassName(),
                    "<init>",
                    "()V")));
            il.append(InstructionConstants.RETURN);

            MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC, // todo this is not to spec it should be protected
                    Type.VOID,
                    Type.NO_ARGS,
                    null,
                    "<init>",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();

            classGen.addMethod(methodGen.getMethod());

            String fileName = classGen.getClassName().replace('.', charfileSeparator) + ".class";
            File dumpFile = new File(outputDir, fileName);
            boolean error = false;
            try {
                classGen.getJavaClass().dump(dumpFile);
            } catch (IOException e) {
                //hide, we could not write out the class
                error = true;

            }

            if (!error){
                // set our next class
                // Print warning
                if (this.classGen.getSuperclassName().equals(classGen.getClassName())){
                    System.out.println("WARNING: persistence capable class '" +
                            this.classGen.getClassName() +
                            "' has a non persistence super class \n'"
                            + classGen.getClassName() +
                            "', that does not have a default constructor, will add one.");
                }

                addDefaultConstructorToNonPersistantSuperClasses(classGen.getSuperclassName());
            }

        } catch (IOException e) {
            // hide exception, this class is not on our classpath
        }
    }


    private void swapClone() {
        // representation of methods in the class
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];

            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()){
                continue;
            }
            //we do not want to enhance our enhanced methods
            if (m.getName().startsWith("<cl")){
                continue;
            }

            boolean changed = false;

            MethodGen mg = new MethodGen(m,classGen.getClassName(),constantPoolGen);

            // get the code in form of an InstructionList object
            InstructionList il = mg.getInstructionList();

            // get the first instruction
            InstructionHandle ih = il.getStart();

            while (ih != null) {
                Instruction ins = ih.getInstruction();
                if (ins.getClass().getName().equals(invokeSpecial)){
                    INVOKESPECIAL is = (INVOKESPECIAL)ins;
                    if (is.getClassName(constantPoolGen).equals("java.lang.Object") &&
                            is.getMethodName(constantPoolGen).equals("clone") &&
                            is.getSignature(constantPoolGen).equals("()Ljava/lang/Object;")) {

                        il.append(is,getCloneIL());
                        il.setPositions();
                        il.update();
                        changed = true;

                    }
                }
                // next instruction
                ih = ih.getNext();
            }
            // don't forget to write the code
            if (changed){
                il.setPositions();
                il.update();
                mg.setMaxLocals();
                mg.setMaxStack();
                classGen.replaceMethod(m,mg.getMethod());
            }
        }
    }

    private InstructionList getCloneIL(){
        InstructionList il = new InstructionList();
        il.append(new DUP());
        il.append(instructionFactory.createCheckCast(new ObjectType(classGen.getClassName())));
        il.append(new ACONST_NULL());
        if (javaVersion >= JAVA_1_4) {
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
        } else {
            il.append(instructionFactory.createPutField(getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
        }
        il.append(new DUP());
        il.append(instructionFactory.createCheckCast(new ObjectType(classGen.getClassName())));
        il.append(new ICONST(0));
        if (javaVersion >= JAVA_1_4) {
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    "jdoFlags",
                    Type.BYTE));
        } else {
            il.append(instructionFactory.createPutField(getTopPCSuperOrCurrentClassName(),
                    "jdoFlags",
                    Type.BYTE));
        }
        return il;


    }


//  private void addJdogenieMakeHollow() {
//
//        InstructionList il = new InstructionList();
//        MethodGen methodGen = new MethodGen(
//                Constants.ACC_PUBLIC ,
//                Type.VOID,
//                new Type[]{},
//                new String[]{},
//                vendorName+"MakeHollow",
//                classGen.getClassName(),
//                il,
//                constantPoolGen);
//
//    for (Iterator iterator = fieldSet.iterator();iterator.hasNext();) {
//      FieldInfo fieldInfo = (FieldInfo) iterator.next();
//      if (fieldInfo.isPrimative() && !fieldInfo.isArray()){
//        continue;
//      }
//      il.append(new ALOAD(0));
//      il.append(new ACONST_NULL());
//      il.append(instructionFactory.createPutField(
//              classGen.getClassName(),
//              fieldInfo.getFieldName(),
//              fieldInfo.getType()));
//
//    }
//    if (classInfo.getPersistenceCapableSuperclass() != null){
//      il.append(new ALOAD(0));
//      il.append(instructionFactory.createInvoke(
//              classInfo.getPersistenceCapableSuperclass() ,
//              vendorName+"MakeHollow" ,
//              Type.VOID ,
//              new Type[]{} ,
//              Constants.INVOKESPECIAL));
//      il.append(new RETURN());
//    } else {
//            il.append(new RETURN());
//    }
//
//        methodGen.setMaxLocals();
//        methodGen.setMaxStack();
//        classGen.addMethod(methodGen.getMethod());
//        il.dispose();
////    classGen.addInterface(MAKE_HOLLOW_INTERFASE);
//    }

  private void dumpClass()throws VerifyException{
        String fileName = classGen.getClassName().replace('.',charfileSeparator)+".class";
        File dumpFile;
        if (outputDir != null){
            dumpFile = new File(outputDir,fileName);
        } else {
            dumpFile = currentOutputFile;
        }
        try {
            classGen.getJavaClass().dump(dumpFile);
        } catch (IOException e) {
            throw new VerifyException(e);
        }

    }



    /** Copy fields to an outside source from the key fields in the ObjectId.
     * This method is generated in the PersistenceCapable class to generate
     * a call to the field manager for each key field in the ObjectId.  For
     * example, an ObjectId class that has three key fields (int id,
     * String name, and Float salary) would have the method generated:
     * <P>void copyKeyFieldsFromObjectId
     * <P>        (PersistenceCapable oid, ObjectIdFieldManager fm) {
     * <P>     fm.storeIntField (0, oid.id);
     * <P>     fm.storeStringField (1, oid.name);
     * <P>     fm.storeObjectField (2, oid.salary);
     * <P>}
     * <P>The implementation is responsible for implementing the
     * ObjectIdFieldManager to store the values for the key fields.
     * private void jdoCopyKeyFieldsFromObjectId(PersistenceCapable.ObjectIdFieldReplacer fm, Object oid){
     */
    private void addJdoCopyKeyFieldsFromObjectId1() {
        if (classInfo.getTopPCSuperClass() == null ||
                (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION && classInfo.getObjectidClass() != null)){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.VOID,
                    new Type[]{
                        new ObjectType("javax.jdo.spi.PersistenceCapable$ObjectIdFieldConsumer"),
                        Type.OBJECT
                    },
                    new String[]{"fc","oid"},
                    "jdoCopyKeyFieldsFromObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                    && classInfo.getObjectidClass() != null) {
                Iterator iter = classInfo.getFieldList().iterator();
                int count = 0;
                boolean isObject = false;
                while (iter.hasNext()){
                    FieldInfo info = (FieldInfo)iter.next();
                    if (info.primaryKey()){
                        String fieldReplacerMethod = null;
                        if (typeToFieldReplacer.containsKey(info.getType())){
                            fieldReplacerMethod = (String)typeToFieldReplacer.get(info.getType());
                            isObject = false;
                        } else {
                            isObject = true;
                        }
                        il.append(new ALOAD(1));
                        il.append(instructionFactory.createGetStatic(
                                classGen.getClassName(),
                                "jdoInheritedFieldCount",
                                Type.INT));
                        il.append(new PUSH(constantPoolGen, count));
                        il.append(new IADD());
                        il.append(new ALOAD(2));
                        il.append(instructionFactory.createCheckCast(new ObjectType(classInfo.getObjectidClass())));
                        il.append(instructionFactory.createGetField(
                                classInfo.getObjectidClass(),
                                info.getFieldName(),
                                info.getType()));

                        if (isObject){
                            il.append(instructionFactory.createInvoke(
                                    "javax.jdo.spi.PersistenceCapable$ObjectIdFieldConsumer",
                                    "storeObjectField",
                                    Type.VOID,
                                    new Type[]{
                                        Type.INT,
                                        Type.OBJECT},
                                    Constants.INVOKEINTERFACE));
                        } else {
                            il.append(instructionFactory.createInvoke(
                                    "javax.jdo.spi.PersistenceCapable$ObjectIdFieldConsumer",
                                    fieldReplacerMethod,
                                    Type.VOID,
                                    new Type[]{
                                        Type.INT,
                                        info.getType()},
                                    Constants.INVOKEINTERFACE));
                        }
                    }
                    count ++;
                }
            }
            il.append(new RETURN());
//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }

    private void addJdoCopyKeyFieldsFromObjectId2(){
        if (classInfo.getTopPCSuperClass() == null ||
                (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                && classInfo.getObjectidClass() != null)) {

            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PROTECTED,
                    Type.VOID,
                    new Type[]{
                        Type.OBJECT
                    },
                    new String[]{"oid"},
                    "jdoCopyKeyFieldsFromObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                    && classInfo.getObjectidClass() != null) {

                il.append(new ALOAD(1));
                il.append(instructionFactory.createCheckCast(new ObjectType(classInfo.getObjectidClass())));
                il.append(new ASTORE(2));
                InstructionHandle pckStartHandle = null;
                boolean first = true;
                ClassInfo currentClass = getTopPCSuperOrCurrentClass();
                Iterator iter = currentClass.getFieldList().iterator();
                while (iter.hasNext()){
                    FieldInfo info = (FieldInfo)iter.next();
                    if (info.primaryKey()){
                        if (first){
                            pckStartHandle = il.append(new ALOAD(0));
                            first = false;
                        } else {
                            il.append(new ALOAD(0));
                        }
                        il.append(new ALOAD(2));
                        il.append(instructionFactory.createGetField(
                                classInfo.getObjectidClass(),
                                info.getFieldName(),
                                info.getType()));
                        il.append(instructionFactory.createPutField(
                                classInfo.getClassName(),
                                info.getFieldName(),
                                info.getType()));
                    }
                }
                il.append(new RETURN());
                methodGen.addLocalVariable(
                        "pck",
                        new ObjectType(classInfo.getObjectidClass()),
                        2,
                        pckStartHandle,
                        il.getEnd());
            } else {
                il.append(new RETURN());
            }
//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }





    private String getTopPCSuperOrCurrentClassName(){
        if (classInfo.getTopPCSuperClass() == null){
            return classInfo.getClassName();
        } else {
            return classInfo.getTopPCSuperClass().getClassName();
        }
    }

    private ClassInfo getTopPCSuperOrCurrentClass(){
        if (classInfo.getTopPCSuperClass() == null){
            return classInfo;
        } else {
            return classInfo.getTopPCSuperClass();
        }
    }

    private void addJdoReplaceFlags(){
        if (classInfo.getTopPCSuperClass() == null){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC ,
                    Type.VOID,
                    new Type[]{},
                    new String[]{},
                    "jdoReplaceFlags",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);

            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            IFNULL ifnull = new IFNULL(null);
            il.append(ifnull);
            il.append(new ALOAD(0));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createInvoke(
                    STATE_MANAGER,
                    "replacingFlags",
                    Type.BYTE,
                    new Type[] {PC_OBJECT_TYPE},
                    Constants.INVOKEINTERFACE));
            il.append(instructionFactory.createPutField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoFlags",
                    Type.BYTE));
            InstructionHandle handle = il.append(new RETURN());
            ifnull.setTarget(handle);
//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();

            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }

    private boolean mustEnhance(Method m){
        String name = m.getName();
      if (name.startsWith(vendorName+"MakeHollow")){
        return false;
      }
        if (name.startsWith(vendorName)){
          return true;
        }else if (name.startsWith("jdo")){
            if (classInfo.isInstanceCallbacks() &&
                    (name.equals("jdoPreStore") || name.equals("jdoPreDelete"))
                    && m.getSignature().equals("()V")){
                return true;
            }
        } else {
            return true;
        }
        return false;
    }

    private void swapGetterAndSetter(){

        // representation of methods in the class
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];

            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()){
                continue;
            }
            //we do not want to enhance our enhanced methods
            if (m.getName().startsWith("<cl")){
                continue;
            }

            if (!mustEnhance(m)){
                continue;
            }

            boolean changed = false;

            MethodGen mg = new MethodGen(m,classGen.getClassName(),constantPoolGen);

            // get the code in form of an InstructionList object
            InstructionList il = mg.getInstructionList();

            // get the first instruction
            InstructionHandle ih = il.getStart();
            while (ih != null) {
                Instruction ins = ih.getInstruction();
                if (ins.getClass().getName().equals(getField)){//if (ins instanceof GETFIELD)
                    GETFIELD is = (GETFIELD)ins;
                    String key = is.getClassName(constantPoolGen) +"|"+ is.getFieldName(constantPoolGen);
                    if (getAndSettersMap.containsKey(key)) {
                        SwapFieldHelper helper = (SwapFieldHelper)getAndSettersMap.get(key);
                        // replace it with our static replacement method
                        ih.setInstruction(instructionFactory.createInvoke(
                                helper.className,
                                helper.jdoGetName,
                                helper.type,
                                new Type[] {
                                    new ObjectType(helper.className)
                                },
                                Constants.INVOKESTATIC));
                        il.setPositions();
                        il.update();

                        changed = true;
                        InstructionHandle prevIhDUP = ih.getPrev();
                        Instruction iffyDup = prevIhDUP.getInstruction();
                        if (iffyDup.getClass().getName().equals(dup)){  // The previos ist was a DUP
                            ih = ih.getPrev();
                            InstructionHandle prevIhALOAD = ih.getPrev();
                            Instruction iffyAload = prevIhALOAD.getInstruction();
                            if (iffyAload.getClass().getName().equals(aload)){ // The ist before that was a ALOAD
                                ALOAD aLoad = (ALOAD)iffyAload;
                                ih.setInstruction(aLoad); // Swap ref out
                                il.setPositions();
                                il.update();
                            }else {
                                ih = ih.getNext();
                            }
                        }
                    }
                } else if (ins.getClass().getName().equals(putField)){
                    PUTFIELD is = (PUTFIELD)ins;
                    String key = is.getClassName(constantPoolGen) +"|"+ is.getFieldName(constantPoolGen);
                    if (getAndSettersMap.containsKey(key)) {
                        SwapFieldHelper helper = (SwapFieldHelper)getAndSettersMap.get(key);
                        // replace it with our static replacement method
                        ih.setInstruction(instructionFactory.createInvoke(
                                helper.className,
                                helper.jdoSetName,
                                Type.VOID,
                                new Type[] {
                                    new ObjectType(helper.className),
                                    helper.type
                                },
                                Constants.INVOKESTATIC));
                        il.setPositions();
                        il.update();
                        changed = true;
                    }
                }
                // next instruction
                ih = ih.getNext();
            }
            if (changed){
                il.setPositions();
                il.update();
                mg.setMaxLocals();
                mg.setMaxStack();
                Method method = mg.getMethod();
                classGen.replaceMethod(m, method);
            }
        }
    }


    private void setEnhancedFieldsPrivate(){
        Field [] fields = classGen.getFields();
        Iterator iter = fieldSet.iterator();
        while (iter.hasNext()){
            FieldInfo info = (FieldInfo)iter.next();
            String fieldname = info.getFieldName();
            for (int i = 0;i < fields.length; i++) {
                Field f = fields[i];
                if (f.getName().equals(fieldname)){
                    if (!f.isPrivate()){
                        f.isProtected(false);
                        f.isPublic(false);
                        f.isPrivate(true);
                    }
                }
            }
        }
    }


    private void addJdoInterface(){
        classGen.addInterface(PERSISTENCE_CAPABLE);
    }


    private void addJdoCopyKeyFieldsToObjectId2(){
        if (classInfo.getTopPCSuperClass() == null ||
                (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION && classInfo.getObjectidClass() != null)) {
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.VOID,
                    new Type[]{
                        new ObjectType("javax.jdo.spi.PersistenceCapable$ObjectIdFieldSupplier"),
                        Type.OBJECT
                    },
                    new String[]{"fs","oid"},
                    "jdoCopyKeyFieldsToObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION && classInfo.getObjectidClass() != null) {
                Iterator iter = classInfo.getFieldList().iterator();
                int count = 0;
                boolean isObject = false;
                while (iter.hasNext()){
                    FieldInfo info = (FieldInfo)iter.next();
                    if (info.primaryKey()){
                        String fieldProviderMethod = null;
                        if (typeToFieldProvider.containsKey(info.getType())){
                            fieldProviderMethod = (String)typeToFieldProvider.get(info.getType());
                            isObject = false;
                        } else {
                            isObject = true;
                        }
                        il.append(new ALOAD(2));
                        il.append(instructionFactory.createCheckCast(new ObjectType(classInfo.getObjectidClass())));
                        il.append(new ALOAD(1));
                        il.append(instructionFactory.createGetStatic(
                                classGen.getClassName(),
                                "jdoInheritedFieldCount",
                                Type.INT));
                        il.append(new PUSH(constantPoolGen, count));
                        il.append(new IADD());
                        if (isObject){
                            il.append(instructionFactory.createInvoke(
                                    "javax.jdo.spi.PersistenceCapable$ObjectIdFieldSupplier",
                                    "fetchObjectField",
                                    Type.OBJECT,
                                    new Type[]{Type.INT},
                                    Constants.INVOKEINTERFACE));
                            il.append(instructionFactory.createCheckCast((ReferenceType)info.getType()));
                        } else {
                            il.append(instructionFactory.createInvoke(
                                    "javax.jdo.spi.PersistenceCapable$ObjectIdFieldSupplier",
                                    fieldProviderMethod,
                                    info.getType(),
                                    new Type[]{Type.INT},
                                    Constants.INVOKEINTERFACE));

                        }
                        il.append(instructionFactory.createPutField(classInfo.getObjectidClass(),
                                                                    info.getFieldName(),
                                                                    info.getType()));

                    }
                    count ++;
                }
            }
            il.append(new RETURN());

//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    // not cool, maybe ???????? test
    private void addJdoCopyKeyFieldsToObjectId1(){
        if (classInfo.getTopPCSuperClass() == null
                || (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                && classInfo.getObjectidClass() != null)) {
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.VOID,
                    new Type[]{
                        Type.OBJECT
                    },
                    new String[]{"oid"},
                    "jdoCopyKeyFieldsToObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                    && classInfo.getObjectidClass() != null) {
                Iterator iter = classInfo.getFieldList().iterator();
                while (iter.hasNext()){
                    FieldInfo info = (FieldInfo)iter.next();
                    if (info.primaryKey()){
                        il.append(new ALOAD(1));
                        il.append(instructionFactory.createCheckCast(
                                new ObjectType(classInfo.getObjectidClass())));
                        il.append(new ALOAD(0));
                        il.append(instructionFactory.createGetField(
                                classInfo.getClassName(),
                                info.getFieldName(),
                                info.getType()));
                        il.append(instructionFactory.createPutField(
                                classInfo.getObjectidClass(),
                                info.getFieldName(),
                                info.getType()));
                    }
                }
            }
            il.append(new RETURN());
//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoNewObjectIdInstance1(){
        if (classInfo.getTopPCSuperClass() == null ||
                (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                && classInfo.getObjectidClass() != null)) {
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.OBJECT,
                    null,
                    null,
                    "jdoNewObjectIdInstance",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                    && classInfo.getObjectidClass() != null) {
                il.append(instructionFactory.createNew(classInfo.getObjectidClass()));
                il.append(new DUP());
                il.append(instructionFactory.createInvoke(
                        classInfo.getObjectidClass(),
                        "<init>",
                        Type.VOID,
                        new Type[]{},
                        Constants.INVOKESPECIAL));
            } else {
                il.append(new ACONST_NULL());
            }
            il.append(new ARETURN());

            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoNewObjectIdInstance2(){
        if (classInfo.getTopPCSuperClass() == null ||
                (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION && classInfo.getObjectidClass() != null)){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.OBJECT,
                    new Type[]{Type.STRING},
                    new String[]{"str"},
                    "jdoNewObjectIdInstance",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION
                    && classInfo.getObjectidClass() != null) {
                il.append(instructionFactory.createNew(classInfo.getObjectidClass()));
                il.append(new DUP());
                il.append(new ALOAD(1));
                il.append(instructionFactory.createInvoke(
                        classInfo.getObjectidClass(),
                        "<init>",
                        Type.VOID,
                        new Type[]{Type.STRING},
                        Constants.INVOKESPECIAL));
            } else {
                il.append(new ACONST_NULL());
            }
            il.append(new ARETURN());

            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }

    private void addJdoReplaceStateManager(){
        if (classInfo.getTopPCSuperClass() == null){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC  | Constants.ACC_SYNCHRONIZED,
                    Type.VOID,
                    new Type[]{SM_OBJECT_TYPE},
                    new String[]{"sm"},
                    "jdoReplaceStateManager",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);


            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            IFNULL ifnullInst1 = new IFNULL(null);
            il.append(ifnullInst1);
            il.append(new ALOAD(0));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ALOAD(0));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke(
                    STATE_MANAGER,
                    "replacingStateManager",
                    SM_OBJECT_TYPE,
                    new Type[]{
                        PC_OBJECT_TYPE,
                        SM_OBJECT_TYPE},
                    Constants.INVOKEINTERFACE));
            il.append(instructionFactory.createPutField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            GOTO gotoInst = new GOTO(null);
            il.append(gotoInst);
            InstructionHandle secManHandle = il.append(instructionFactory.createInvoke(
                    "java.lang.System",
                    "getSecurityManager",
                    new ObjectType("java.lang.SecurityManager"),
                    new Type[]{},
                    Constants.INVOKESTATIC));
            ifnullInst1.setTarget(secManHandle);
            il.append(new ASTORE(2));
            InstructionHandle startSecHandle = il.append(new ALOAD(2));
            IFNULL ifnullInst2 = new IFNULL(null);
            il.append(ifnullInst2);
            il.append(new ALOAD(2));
            il.append(instructionFactory.createGetStatic(
                    "javax.jdo.spi.JDOPermission",
                    "SET_STATE_MANAGER",
                    new ObjectType("javax.jdo.spi.JDOPermission")));
            il.append(instructionFactory.createInvoke(
                    "java.lang.SecurityManager",
                    "checkPermission",
                    Type.VOID,
                    new Type[]{new ObjectType("java.security.Permission")},
                    Constants.INVOKEVIRTUAL));
            InstructionHandle ifnullHandle = il.append(new ALOAD(0));
            ifnullInst2.setTarget(ifnullHandle);
            il.append(new ALOAD(1));
            il.append(instructionFactory.createPutField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            InstructionHandle gotoHandle = il.append(new RETURN());
            gotoInst.setTarget(gotoHandle);
            methodGen.addLocalVariable(
                    "sec",
                    new ObjectType("java.lang.SecurityManager"),
                    2,
                    startSecHandle,
                    il.getEnd());


            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }

    }


    private void addJdoGetTransactionalObjectId(){
        if (classInfo.getTopPCSuperClass() == null){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.OBJECT,
                    new Type[]{},
                    new String[]{},
                    "jdoGetTransactionalObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            IFNONNULL ifnonnullInst = new IFNONNULL(null);
            il.append(ifnonnullInst);
            il.append(new ACONST_NULL());
            GOTO gotoInst = new GOTO(null);
            il.append(gotoInst);
            InstructionHandle ifnonnullHandle = il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createInvoke(
                    STATE_MANAGER,
                    "getTransactionalObjectId",
                    Type.OBJECT,
                    new Type[]{PC_OBJECT_TYPE},
                    Constants.INVOKEINTERFACE));
            InstructionHandle gotoHandle = il.append(new ARETURN());
            gotoInst.setTarget(gotoHandle);
            ifnonnullInst.setTarget(ifnonnullHandle);

//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoGetObjectId(){
        if (classInfo.getTopPCSuperClass() == null){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC,
                    Type.OBJECT,
                    new Type[]{},
                    new String[]{},
                    "jdoGetObjectId",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);


            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            IFNONNULL ifnonnullInst = new IFNONNULL(null);
            il.append(ifnonnullInst);
            il.append(new ACONST_NULL());
            GOTO gotoInst = new GOTO(null);
            il.append(gotoInst);
            InstructionHandle ifnonnullHandle = il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createInvoke(
                    STATE_MANAGER,
                    "getObjectId",
                    Type.OBJECT,
                    new Type[]{PC_OBJECT_TYPE},
                    Constants.INVOKEINTERFACE));
            InstructionHandle gotoHandle = il.append(new ARETURN());
            gotoInst.setTarget(gotoHandle);
            ifnonnullInst.setTarget(ifnonnullHandle);

//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoNewInstance2(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC,
                PC_OBJECT_TYPE,
                new Type[]{SM_OBJECT_TYPE,Type.OBJECT},
                new String[]{"sm","oid"},
                "jdoNewInstance",
                classGen.getClassName(),
                il,
                constantPoolGen);
        if (classGen.isAbstract()){
            il.append(instructionFactory.createNew("javax.jdo.JDOFatalInternalException"));
            il.append(new DUP());
            il.append(instructionFactory.createInvoke(
                    "javax.jdo.JDOFatalInternalException",
                    "<init>",
                    Type.VOID,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
            il.append(new ATHROW());

        } else {
            if (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_DATASTORE){   // datastore
                il.append(instructionFactory.createNew(classGen.getClassName()));
                il.append(new DUP());
                il.append(instructionFactory.createInvoke(
                        classGen.getClassName(),
                        "<init>",
                        Type.VOID ,
                        new Type[]{},
                        Constants.INVOKESPECIAL));
                il.append(new ASTORE(3));
                InstructionHandle pcStartHandle = il.append(new ALOAD(3));
                il.append(new ALOAD(1));
                il.append(instructionFactory.createPutField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoStateManager",
                        SM_OBJECT_TYPE));
                il.append(new ALOAD(3));
                il.append(new ICONST(1));
                il.append(instructionFactory.createPutField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoFlags",
                        Type.BYTE));
                il.append(new ALOAD(3));
                InstructionHandle returnHandle = il.append(new ARETURN());
                methodGen.addLocalVariable("pc", new ObjectType(classGen.getClassName()), 3, pcStartHandle, returnHandle);
            } else {// this class has application Identity
                il.append(instructionFactory.createNew(classGen.getClassName()));
                il.append(new DUP());
                il.append(instructionFactory.createInvoke(
                        classGen.getClassName(),
                        "<init>",
                        Type.VOID ,
                        new Type[]{},
                        Constants.INVOKESPECIAL));
                il.append(new ASTORE(3));
                InstructionHandle pcStartHandle = il.append(new ALOAD(3));
                il.append(new ALOAD(1));
                il.append(instructionFactory.createPutField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoStateManager",
                        SM_OBJECT_TYPE));
                il.append(new ALOAD(3));
                il.append(new ICONST(1));
                il.append(instructionFactory.createPutField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoFlags",
                        Type.BYTE));
                il.append(new ALOAD(0));
                il.append(new ALOAD(2));
                il.append(instructionFactory.createInvoke(
                        getTopPCSuperOrCurrentClass().getClassName(),
                        "jdoCopyKeyFieldsFromObjectId",
                        Type.VOID ,
                        new Type[]{Type.OBJECT},
                        Constants.INVOKEVIRTUAL));

                il.append(new ALOAD(3));
                il.append(new ARETURN());
                methodGen.addLocalVariable("pc", new ObjectType(classGen.getClassName()), 3, pcStartHandle, il.getEnd());
            }
        }

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }


    private void addJdoNewInstance1(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC,
                PC_OBJECT_TYPE,
                new Type[]{SM_OBJECT_TYPE},
                new String[]{"sm"},
                "jdoNewInstance",
                classGen.getClassName(),
                il,
                constantPoolGen);
        if (classGen.isAbstract()){
            il.append(instructionFactory.createNew("javax.jdo.JDOFatalInternalException"));
            il.append(new DUP());
            il.append(instructionFactory.createInvoke(
                    "javax.jdo.JDOFatalInternalException",
                    "<init>",
                    Type.VOID,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
            il.append(new ATHROW());
        } else {
            il.append(instructionFactory.createNew(classGen.getClassName()));
            il.append(new DUP());
            il.append(instructionFactory.createInvoke(
                    classGen.getClassName(),
                    "<init>",
                    Type.VOID ,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
            il.append(new ASTORE(2));
            InstructionHandle pcStartHandle = il.append(new ALOAD(2));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createPutField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ALOAD(2));
            il.append(new ICONST(1));
            il.append(instructionFactory.createPutField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoFlags",
                    Type.BYTE));
            il.append(new ALOAD(2));
            InstructionHandle returnHandle = il.append(new ARETURN());
            methodGen.addLocalVariable(
                    "pc",
                    new ObjectType(classGen.getClassName()),
                    2,
                    pcStartHandle,
                    returnHandle);
        }

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }


    private void addRegisterClass(){
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();
        InstructionHandle returnHandle = il.getEnd();//The last instruction of <clinit> will always be the return

        String className = getSetClass$Field(classGen.getClassName());
        InstructionHandle nopTarget = il.append(new NOP());
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                className,
                new ObjectType("java.lang.Class")));
        IFNONNULL ifnonnull = new IFNONNULL(null);
        il.append(ifnonnull);
        il.append(new PUSH(constantPoolGen ,classGen.getClassName()));
        il.append(instructionFactory.createInvoke(
                classGen.getClassName(),
                "class$",
                new ObjectType("java.lang.Class") ,
                new Type[]{Type.STRING},
                Constants.INVOKESTATIC));
        il.append(new DUP());
        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                className,
                new ObjectType("java.lang.Class")));
        GOTO gotoIns = new GOTO(null);
        il.append(gotoIns);
        InstructionHandle ifnonnullHandle = il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                className,
                new ObjectType("java.lang.Class")));
        ifnonnull.setTarget(ifnonnullHandle);
        InstructionHandle gotoHandle = il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoFieldNames",
                new ArrayType("java.lang.String",1)));
        gotoIns.setTarget(gotoHandle);
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoFieldTypes",
                new ArrayType("java.lang.Class",1)));
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoFieldFlags",
                new ArrayType(Type.BYTE,1)));
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoPersistenceCapableSuperclass",
                new ObjectType("java.lang.Class")));
        if (classGen.isAbstract()){
            il.append(new ACONST_NULL());
        } else {
            il.append(instructionFactory.createNew(classGen.getClassName()));
            il.append(new DUP());
            il.append(instructionFactory.createInvoke(
                    classGen.getClassName(),
                    "<init>",
                    Type.VOID ,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
        }
        il.append(instructionFactory.createInvoke(
                "javax.jdo.spi.JDOImplHelper",
                "registerClass",
                Type.VOID ,
                new Type[]{
                    new ObjectType("java.lang.Class"),
                    new ArrayType(Type.STRING,1),
                    new ArrayType("java.lang.Class",1),
                    new ArrayType(Type.BYTE,1),
                    new ObjectType("java.lang.Class"),
                    PC_OBJECT_TYPE
                },
                Constants.INVOKESTATIC));
        il.append(new RETURN());
        try{
            il.delete(returnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }
        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m, methodGen.getMethod());
        il.dispose();
    }


    private boolean writeObjectExist(){
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName().equals("writeObject") &&
                    m.getSignature().equals("(Ljava/io/ObjectOutputStream;)V")){
                return true;
            }
        }
        return false;

    }

    private Method getWriteObject() {
        Method[] methods = classGen.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName().equals("writeObject") &&
                    m.getSignature().equals("(Ljava/io/ObjectOutputStream;)V")) {
                return m;
            }
        }
        return null;

    }

    private boolean readObjectExist() {
        Method[] methods = classGen.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName().equals("readObject") &&
                    m.getSignature().equals("(Ljava/io/ObjectInputStream;)V")) {
                return true;
            }
        }
        return false;

    }

    private Method getReadObject() {
        Method[] methods = classGen.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName().equals("readObject") &&
                    m.getSignature().equals("(Ljava/io/ObjectInputStream;)V")) {
                return m;
            }
        }
        return null;

    }


    private void addWriteObject(){
        boolean rename = false;
        if (writeObjectExist()
                && classInfo.getTopPCSuperClass() == null) {
            // we must rename this method
            Method m = getWriteObject();
            MethodGen mg = new MethodGen(m, classGen.getClassName(), constantPoolGen);
            mg.setName("versantWriteObject");
            classGen.replaceMethod(m,mg.getMethod());
            rename = true;
        } else if (writeObjectExist() && classInfo.getTopPCSuperClass() != null){
            return;
        }
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PRIVATE,
                Type.VOID,
                new Type[]{new ObjectType("java.io.ObjectOutputStream")},
                new String[]{"out"},
                "writeObject",
                classGen.getClassName(),
                il,
                constantPoolGen);
        if (classInfo.getTopPCSuperClass() == null){
            il.append(new ALOAD(0));
            il.append(instructionFactory.createInvoke(
                    getTopPCSuperOrCurrentClass().getClassName(),
                    "jdoPreSerialize",
                    Type.VOID ,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
        }
        if (rename){
            il.append(new ALOAD(0));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke(
                    classGen.getClassName(),
                    "versantWriteObject",
                    Type.VOID,
                    new Type[]{new ObjectType("java.io.ObjectOutputStream")},
                    Constants.INVOKESPECIAL));
        } else {
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke(
                    "java.io.ObjectOutputStream",
                    "defaultWriteObject",
                    Type.VOID ,
                    new Type[]{},
                    Constants.INVOKEVIRTUAL));
        }

        if (classInfo.getTopPCSuperClass() == null && detach){
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    "jdoStateManager",
                    new ObjectType(STATE_MANAGER)));
            il.append(new INSTANCEOF(constantPoolGen.addClass(DETACHED_STATE_MANAGER)));
            IFEQ ifeq = new IFEQ(null);
            il.append(ifeq);
            il.append(new ALOAD(1));
            il.append(new ICONST(1));
            il.append(instructionFactory.createInvoke("java.io.ObjectOutputStream",
                    "writeBoolean",
                    Type.VOID,
                    new Type[]{Type.BOOLEAN},
                    Constants.INVOKEVIRTUAL));
            il.append(new ALOAD(1));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    "jdoStateManager",
                    new ObjectType(STATE_MANAGER)));
            il.append(instructionFactory.createInvoke("java.io.ObjectOutputStream",
                    "writeObject",
                    Type.VOID,
                    new Type[]{Type.OBJECT},
                    Constants.INVOKEVIRTUAL));
            il.append(new ALOAD(1));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    "jdoFlags",
                    Type.BYTE));
            il.append(instructionFactory.createInvoke("java.io.ObjectOutputStream",
                    "writeByte",
                    Type.VOID,
                    new Type[]{Type.INT},
                    Constants.INVOKEVIRTUAL));
            GOTO aGoto = new GOTO(null);
            il.append(aGoto);
            InstructionHandle aload1Handle = il.append(new ALOAD(1));
            ifeq.setTarget(aload1Handle);
            il.append(new ICONST(0));
            il.append(instructionFactory.createInvoke("java.io.ObjectOutputStream",
                    "writeBoolean",
                    Type.VOID,
                    new Type[]{Type.BOOLEAN},
                    Constants.INVOKEVIRTUAL));
            InstructionHandle returnHandle = il.append(new RETURN());
            aGoto.setTarget(returnHandle);
        } else {
            il.append(new RETURN());
        }

        methodGen.addException("java.io.IOException");
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }

    private void addReadObject() {
        if (classInfo.getTopPCSuperClass() == null && detach) {
            boolean rename = false;
            if (readObjectExist()) {
                // we must rename this method
                Method m = getReadObject();
                MethodGen mg = new MethodGen(m, classGen.getClassName(), constantPoolGen);
                mg.setName("versantReadObject");
                classGen.replaceMethod(m, mg.getMethod());
                rename = true;
            }

            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(Constants.ACC_PRIVATE,
                    Type.VOID,
                    new Type[]{new ObjectType("java.io.ObjectInputStream")},
                    new String[]{"in"},
                    "readObject",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);

            if (rename){
                il.append(new ALOAD(0));
                il.append(new ALOAD(1));  il.append(instructionFactory.createInvoke(
                        classGen.getClassName(),
                        "versantReadObject",
                        Type.VOID,
                        new Type[]{new ObjectType("java.io.ObjectInputStream")},
                        Constants.INVOKESPECIAL));


            } else {
                il.append(new ALOAD(1));
                il.append(instructionFactory.createInvoke("java.io.ObjectInputStream",
                        "defaultReadObject",
                        Type.VOID,
                        new Type[]{},
                        Constants.INVOKEVIRTUAL));
            }
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke("java.io.ObjectInputStream",
                    "readBoolean",
                    Type.BOOLEAN,
                    new Type[]{},
                    Constants.INVOKEVIRTUAL));
            IFEQ ifeq = new IFEQ(null);
            il.append(ifeq);//22
            il.append(new ALOAD(0));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke("java.io.ObjectInputStream",
                    "readObject",
                    Type.OBJECT,
                    new Type[]{},
                    Constants.INVOKEVIRTUAL));
            il.append(instructionFactory.createCheckCast(new ObjectType(DETACHED_STATE_MANAGER)));
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    "jdoStateManager",
                    new ObjectType(STATE_MANAGER)));
            il.append(new ALOAD(0));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke("java.io.ObjectInputStream",
                    "readByte",
                    Type.BYTE,
                    new Type[]{},
                    Constants.INVOKEVIRTUAL));
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    "jdoFlags",
                    Type.BYTE));


            InstructionHandle returnHandle = il.append(new RETURN());
            ifeq.setTarget(returnHandle);

            methodGen.addException("java.io.IOException");
            methodGen.addException("java.lang.ClassNotFoundException");
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoPreSerialize(){
        if (classInfo.getTopPCSuperClass() == null){
            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PRIVATE,
                    Type.VOID,
                    new Type[]{},
                    new String[]{},
                    "jdoPreSerialize",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);

            InstructionHandle returnHandle = il.insert(new RETURN());
            il.insert(instructionFactory.createInvoke(
                    STATE_MANAGER,
                    "preSerialize",
                    Type.VOID ,
                    new Type[]{PC_OBJECT_TYPE},
                    Constants.INVOKEINTERFACE));
            il.insert(new ALOAD(0));
            il.insert(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.insert(new ALOAD(0));
            il.insert(new IFNULL(returnHandle));
            il.insert(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.insert(new ALOAD(0));

//            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
        }
    }


    private void addJdoCopyFields(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC,
                Type.VOID,
                new Type[]{Type.OBJECT, new ArrayType(Type.INT,1)},
                new String[]{"pc","fieldNumbers"},
                "jdoCopyFields",
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(1));
        il.append(instructionFactory.createCheckCast(new ObjectType(classGen.getClassName())));
        il.append(new ASTORE(3));
        InstructionHandle otherStartHandle = il.append(new ALOAD(3));
        il.append(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        il.append(new ALOAD(0));
        il.append(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        IF_ACMPEQ if_acmpeq = new IF_ACMPEQ(null);
        il.append(if_acmpeq);
        il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
        il.append(new DUP());
        il.append(new PUSH(constantPoolGen,"this.jdoStateManager != other.jdoStateManager"));
        il.append(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
        il.append(new ATHROW());
        InstructionHandle if_acmpeqHandle = il.append(new ALOAD(0));
        if_acmpeq.setTarget(if_acmpeqHandle);
        il.append(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        IFNONNULL ifnonnull = new IFNONNULL(null);
        il.append(ifnonnull);
        il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
        il.append(new DUP());
        il.append(new PUSH(constantPoolGen,"this.jdoStateManager == null"));
        il.append(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
        il.append(new ATHROW());
        InstructionHandle ifnonnullHandle = il.append(new ICONST(0));
        ifnonnull.setTarget(ifnonnullHandle);
        il.append(new ISTORE(4));
        GOTO aGoto = new GOTO(null);
        InstructionHandle iStartHandle = il.append(aGoto);
        InstructionHandle if_icmpltHandle = il.append(new ALOAD(0));
        il.append(new ALOAD(3));
        il.append(new ALOAD(2));
        il.append(new ILOAD(4));
        il.append(new IALOAD());
        il.append(instructionFactory.createInvoke(
                classGen.getClassName(),
                "jdoCopyField",
                Type.VOID,
                new Type[]{new ObjectType(classGen.getClassName()),Type.INT},
                Constants.INVOKEVIRTUAL));
        il.append(new IINC(4,1));
        InstructionHandle aGotoHandle = il.append(new ILOAD(4));
        aGoto.setTarget(aGotoHandle);
        il.append(new ALOAD(2));
        il.append(new ARRAYLENGTH());
        il.append(new IF_ICMPLT(if_icmpltHandle));
        il.append(new RETURN());

        methodGen.addLocalVariable("other", new ObjectType(classGen.getClassName()), 3, otherStartHandle, il.getEnd());
        methodGen.addLocalVariable("i", Type.INT, 4, iStartHandle, il.getEnd());
//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }


    private void addJdoCopyField(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC,
                Type.VOID,
                new Type[]{new ObjectType(classGen.getClassName()), Type.INT},
                new String[]{"other","fieldNumber"},
                "jdoCopyField",
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ILOAD(2));
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoInheritedFieldCount",
                Type.INT));
        il.append(new ISUB());
        il.append(new ISTORE(3));
        InstructionHandle relativeFieldStartHandle = il.append(new ILOAD(3));

        int switchCount = fieldSet.size();
        int[] match = new int[switchCount];
        InstructionHandle[] targets = new InstructionHandle[switchCount];
        ArrayList tempInsLists = new ArrayList(switchCount+1);
        int i = 0;
        ArrayList tempList = new ArrayList(fieldSet);
        for (Iterator fieldIter = tempList.iterator(); fieldIter.hasNext();i++) {
            FieldInfo fieldInfo = (FieldInfo)fieldIter.next();
            InstructionList tempIL = new InstructionList();
            match[i] = fieldInfo.getFieldNo();
            targets[i] = tempIL.append(new ALOAD(0));
            tempIL.append(new ALOAD(1));
            tempIL.append(instructionFactory.createGetField(
                    classGen.getClassName(),
                    fieldInfo.getFieldName(),
                    fieldInfo.getType()));
            tempIL.append(instructionFactory.createPutField(
                    classGen.getClassName(),
                    fieldInfo.getFieldName(),
                    fieldInfo.getType()));
            tempIL.append(new RETURN());
            tempInsLists.add(tempIL);
        }
        // Do default
        InstructionList tempIL = new InstructionList();
        InstructionHandle defaultHandle = null;
        if (classInfo.getTopPCSuperClass() == null){
            defaultHandle = tempIL.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
            tempIL.append(new DUP());
            tempIL.append(new PUSH(constantPoolGen,"fieldNumber"));
            tempIL.append(instructionFactory.createInvoke(
                    "java.lang.IllegalArgumentException",
                    "<init>",
                    Type.VOID ,
                    new Type[]{Type.STRING},
                    Constants.INVOKESPECIAL));
            tempIL.append(new ATHROW());
        } else {
            defaultHandle = tempIL.append(new ALOAD(0));
            tempIL.append(new ALOAD(1));
            tempIL.append(new ILOAD(2));
            tempIL.append(instructionFactory.createInvoke(
                    classInfo.getTopPCSuperClass().getClassName(),
                    "jdoCopyField",
                    Type.VOID,
                    new Type[]{new ObjectType(classInfo.getTopPCSuperClass().getClassName()),
                               Type.INT},
                    Constants.INVOKESPECIAL));
        }
        tempInsLists.add(tempIL);
        // start the lookupSwitch
        il.append(new LOOKUPSWITCH(match,targets,defaultHandle));
        for (Iterator tempIlIter = tempInsLists.iterator(); tempIlIter.hasNext();) {   // add all instructions
            InstructionList list = (InstructionList) tempIlIter.next();
            il.append(list);
        }
        il.append(new RETURN());

        methodGen.addLocalVariable("relativeField", Type.INT, 3, relativeFieldStartHandle, il.getEnd());

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }


    private void addJdoProvideFields(){

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC ,
                Type.VOID,
                new Type[]{new ArrayType(Type.INT,1)},
                new String[]{"fieldNumbers"},
                "jdoProvideFields",
                classGen.getClassName(),
                il,
                constantPoolGen);
        il.append(new ICONST(0));
        il.append(new ISTORE(2));
        InstructionHandle iloadHandle = il.append(new ILOAD(2));
        il.append(new ALOAD(1));
        il.append(new ARRAYLENGTH());
        IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
        il.append(if_icmpge);
        il.append(new ALOAD(1));
        il.append(new ILOAD(2));
        il.append(new IALOAD());
        il.append(new ISTORE(3));
        InstructionHandle aloadHandle = il.append(new ALOAD(0));
        il.append(new ILOAD(3));
        il.append(instructionFactory.createInvoke(
                classGen.getClassName(),
                "jdoProvideField",
                Type.VOID ,
                new Type[]{Type.INT},
                Constants.INVOKEVIRTUAL));
        InstructionHandle iincHandle = il.append(new IINC(2,1));
        il.append(new GOTO(iloadHandle));
        InstructionHandle returnHandle = il.append(new RETURN());
        if_icmpge.setTarget(returnHandle);
        methodGen.addLocalVariable("i",Type.INT,2,iloadHandle,returnHandle);
        methodGen.addLocalVariable("fieldNumber",Type.INT,3,aloadHandle,iincHandle);
//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

  private void addJdoProvideField(){

    ArrayList myList = new ArrayList(fieldSet);
    ListIterator fieldIter = myList.listIterator();

    while (fieldIter.hasNext()){fieldIter.next();}

    InstructionList il = new InstructionList();

    MethodGen methodGen = new MethodGen(
            Constants.ACC_PUBLIC,
            Type.VOID,
            new Type[]{Type.INT},
            new String[]{"fieldNumber"},
            "jdoProvideField",
            classGen.getClassName(),
            il,
            constantPoolGen);

    if (!isEmpty){
      int size = fieldSet.size();
      int[] match = new int[size];
      int fieldNum = size;
      InstructionHandle[] targets = new InstructionHandle[size];
      InstructionHandle defaultHandle = null;
      InstructionHandle returnHandel = null;
      Set switchList = new TreeSet();
      if (classInfo.getPersistenceCapableSuperclass() == null){
        defaultHandle = il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
        il.append(new DUP());

                il.append(instructionFactory.createNew("java.lang.StringBuffer"));
                il.append(new DUP());
                il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "<init>",
                        Type.VOID,
                        new Type[]{},
                        Constants.INVOKESPECIAL));
                il.append(new PUSH(constantPoolGen, "Class " + classGen.getClassName() +
                        " called with invalid fieldNumber = "));
                il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "append",
                        Type.STRINGBUFFER,
                        new Type[]{Type.STRING},
                        Constants.INVOKEVIRTUAL));
                il.append(new ILOAD(1));
                il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "append",
                        Type.STRINGBUFFER,
                        new Type[]{Type.INT},
                        Constants.INVOKEVIRTUAL));
                il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "toString",
                        Type.STRING,
                        new Type[]{},
                        Constants.INVOKEVIRTUAL));

        il.append(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID ,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
        il.append(new ATHROW());
        returnHandel = il.append(new RETURN());
      } else {
        returnHandel = il.insert(new RETURN());
        il.insert(new ATHROW());
        il.insert(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID ,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
//        il.insert(new PUSH(constantPoolGen,"fieldNumber"));

                il.insert(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "toString",
                        Type.STRING,
                        new Type[]{},
                        Constants.INVOKEVIRTUAL));
                il.insert(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "append",
                        Type.STRINGBUFFER,
                        new Type[]{Type.INT},
                        Constants.INVOKEVIRTUAL));
                il.insert(new ILOAD(1));
                il.insert(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "append",
                        Type.STRINGBUFFER,
                        new Type[]{Type.STRING},
                        Constants.INVOKEVIRTUAL));
                il.insert(new PUSH(constantPoolGen, "Class " + classGen.getClassName() +
                        " called with invalid fieldNumber = "));
                il.insert(instructionFactory.createInvoke("java.lang.StringBuffer",
                        "<init>",
                        Type.VOID,
                        new Type[]{},
                        Constants.INVOKESPECIAL));
                il.insert(new DUP());
                il.insert(instructionFactory.createNew("java.lang.StringBuffer"));


        il.insert(new DUP());
        InstructionHandle newHandel = il.insert(instructionFactory.createNew("java.lang.IllegalArgumentException"));
        il.insert(new GOTO(returnHandel));
        il.insert(instructionFactory.createInvoke(
                classInfo.getPersistenceCapableSuperclass(),
                "jdoProvideField",
                Type.VOID ,
                new Type[]{Type.INT},
                Constants.INVOKESPECIAL));
        il.insert(new ILOAD(1));
        il.insert(new ALOAD(0));
        il.insert(new IFGE(newHandel));
        defaultHandle = il.insert(new ILOAD(2));
      }

      while (fieldIter.hasPrevious()){
        FieldInfo fieldInfo = (FieldInfo)fieldIter.previous();
        fieldNum --;
        Type fieldType = fieldInfo.getType();
        String stateManagerProvidedField = null;
        boolean isObject = false;
        if (typeToProvidedField.containsKey(fieldInfo.getType())){
          stateManagerProvidedField = (String)typeToProvidedField.get(fieldInfo.getType());
          isObject = false;
        } else {
          isObject = true;
        }

        il.insert(new GOTO(returnHandel));

        if (isObject){
          il.insert(instructionFactory.createInvoke(
                  STATE_MANAGER,
                  "providedObjectField",
                  Type.VOID ,
                  new Type[]{PC_OBJECT_TYPE,Type.INT,Type.OBJECT},
                  Constants.INVOKEINTERFACE));
        } else {
          il.insert(instructionFactory.createInvoke(
                  STATE_MANAGER,
                  stateManagerProvidedField,
                  Type.VOID,
                  new Type[]{PC_OBJECT_TYPE,Type.INT,fieldType},
                  Constants.INVOKEINTERFACE));
        }
        il.insert(instructionFactory.createGetField(
                classGen.getClassName(),
                fieldInfo.getFieldName(),
                fieldType));

        il.insert(new ALOAD(0));
        il.insert(new ILOAD(1));
        il.insert(new ALOAD(0));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        InstructionHandle switchHandel = il.insert(new ALOAD(0));
        TableSwitchHelper tsh = new TableSwitchHelper();
        tsh.match = fieldNum;
        tsh.target = switchHandel;
        switchList.add(tsh);

      }
      Iterator sIter = switchList.iterator();
      int count = 0;
      while (sIter.hasNext()){
        TableSwitchHelper tsh = (TableSwitchHelper)sIter.next();
        match[count] = tsh.match;
        targets[count] = tsh.target;
        count ++;
      }

      il.insert(new TABLESWITCH(match,targets,defaultHandle));
      InstructionHandle relativeFieldFromHandle = il.insert(new ILOAD(2));
      il.insert(new ISTORE(2));
      il.insert(new ISUB());
      il.insert(instructionFactory.createGetStatic(
              classGen.getClassName(),
              "jdoInheritedFieldCount",
              Type.INT));
      il.insert(new ILOAD(1));
      methodGen.addLocalVariable("relativeField",Type.INT,2,relativeFieldFromHandle,returnHandel);
    } else if (classInfo.getPersistenceCapableSuperclass() != null){


            il.append(new ILOAD(1));
      il.append(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    "jdoInheritedFieldCount",
                    Type.INT));
      il.append(new ISUB());
            il.append(new ISTORE(2));
      InstructionHandle relativeField_Start = il.append(new ILOAD(2));
      IFGE ifge = new IFGE(null);
      il.append(ifge);
      il.append(new ALOAD(0));
      il.append(new ILOAD(1));
      il.append(instructionFactory.createInvoke(
                classInfo.getPersistenceCapableSuperclass(),
                "jdoProvideField",
                Type.VOID ,
                new Type[]{Type.INT},
                Constants.INVOKESPECIAL));
      GOTO aGoto = new GOTO(null);
      il.append(aGoto);
      InstructionHandle newHandel = il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
      ifge.setTarget(newHandel);
      il.append(new DUP());
//      il.append(new PUSH(constantPoolGen,"fieldNumber"));
            il.append(instructionFactory.createNew("java.lang.StringBuffer"));
            il.append(new DUP());
            il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                    "<init>",
                    Type.VOID,
                    new Type[]{},
                    Constants.INVOKESPECIAL));
            il.append(new PUSH(constantPoolGen, "Class "+classGen.getClassName() +
                    " called with invalid fieldNumber = "));
            il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                    "append",
                    Type.STRINGBUFFER,
                    new Type[]{Type.STRING},
                    Constants.INVOKEVIRTUAL));
            il.append(new ILOAD(1));
            il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                    "append",
                    Type.STRINGBUFFER,
                    new Type[]{Type.INT},
                    Constants.INVOKEVIRTUAL));
            il.append(instructionFactory.createInvoke("java.lang.StringBuffer",
                    "toString",
                    Type.STRING,
                    new Type[]{},
                    Constants.INVOKEVIRTUAL));
            
      il.append(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID ,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
      il.append(new ATHROW());
      il.append(new RETURN());
      aGoto.setTarget(il.getEnd());

      methodGen.addLocalVariable("relativeField",Type.INT,2,relativeField_Start,il.getEnd());

    } else {
      il.append(new RETURN());
    }
//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
    methodGen.setMaxStack();
    classGen.addMethod(methodGen.getMethod());
    il.dispose();
  }

    private void addJdoReplaceFields(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC ,
                Type.VOID,
                new Type[]{new ArrayType(Type.INT,1)},
                new String[]{"fieldNumbers"},
                "jdoReplaceFields",
                classGen.getClassName(),
                il,
                constantPoolGen);
        il.append(new ICONST(0));
        il.append(new ISTORE(2));
        InstructionHandle iloadHandle = il.append(new ILOAD(2));
        il.append(new ALOAD(1));
        il.append(new ARRAYLENGTH());
        IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
        il.append(if_icmpge);
        il.append(new ALOAD(1));
        il.append(new ILOAD(2));
        il.append(new IALOAD());
        il.append(new ISTORE(3));
        InstructionHandle aloadHandle = il.append(new ALOAD(0));
        il.append(new ILOAD(3));
        il.append(instructionFactory.createInvoke(
                classGen.getClassName(),
                "jdoReplaceField",
                Type.VOID ,
                new Type[]{Type.INT},
                Constants.INVOKEVIRTUAL));
        InstructionHandle iincHandle = il.append(new IINC(2,1));
        il.append(new GOTO(iloadHandle));
        InstructionHandle returnHandle = il.append(new RETURN());
        if_icmpge.setTarget(returnHandle);
        methodGen.addLocalVariable("i",Type.INT,2,iloadHandle,returnHandle);
        methodGen.addLocalVariable("fieldNumber",Type.INT,3,aloadHandle,iincHandle);
//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addJdoReplaceField(){

        int size = fieldSet.size();
        int[] match = new int[size];
        InstructionHandle[] targets = new InstructionHandle[size];
        InstructionHandle defaultHandle = null;
        InstructionHandle returnHandel = null;
        Set switchList = new TreeSet();
        ArrayList myList = new ArrayList(fieldSet);
        ListIterator fieldIter = myList.listIterator();
        int fieldNum = size;
        while (fieldIter.hasNext()){fieldIter.next();}
        InstructionList il = new InstructionList();

        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC,
                Type.VOID,
                new Type[]{Type.INT},
                new String[]{"fieldNumber"},
                "jdoReplaceField",
                classGen.getClassName(),
                il,
                constantPoolGen);
        if (!isEmpty){
            if (classInfo.getPersistenceCapableSuperclass() == null){
                defaultHandle = il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
                il.append(new DUP());
                il.append(new PUSH(constantPoolGen,"fieldNumber"));
                il.append(instructionFactory.createInvoke(
                        "java.lang.IllegalArgumentException",
                        "<init>",
                        Type.VOID ,
                        new Type[]{Type.STRING},
                        Constants.INVOKESPECIAL));
                il.append(new ATHROW());
                returnHandel = il.append(new RETURN());
            } else {
                returnHandel = il.insert(new RETURN());
                il.insert(new ATHROW());
                il.insert(instructionFactory.createInvoke(
                        "java.lang.IllegalArgumentException",
                        "<init>",
                        Type.VOID ,
                        new Type[]{Type.STRING},
                        Constants.INVOKESPECIAL));
                il.insert(new PUSH(constantPoolGen,"fieldNumber"));
                il.insert(new DUP());
                InstructionHandle newHandel = il.insert(instructionFactory.createNew("java.lang.IllegalArgumentException"));
                il.insert(new GOTO(returnHandel));
                il.insert(instructionFactory.createInvoke(
                        classInfo.getPersistenceCapableSuperclass(),
                        "jdoReplaceField",
                        Type.VOID ,
                        new Type[]{Type.INT},
                        Constants.INVOKESPECIAL));
                il.insert(new ILOAD(1));
                il.insert(new ALOAD(0));
                il.insert(new IFGE(newHandel));
                defaultHandle = il.insert(new ILOAD(2));
            }

            while (fieldIter.hasPrevious()){
                FieldInfo fieldInfo = (FieldInfo)fieldIter.previous();
                fieldNum --;
                Type fieldType = fieldInfo.getType();
                String stateManagerReplaceField = null;
                boolean isObject = false;
                if (typeToReplacingField.containsKey(fieldInfo.getType())){
                    stateManagerReplaceField = (String)typeToReplacingField.get(fieldInfo.getType());
                    isObject = false;
                } else {
                    isObject = true;
                }

                il.insert(new GOTO(returnHandel));
                il.insert(instructionFactory.createPutField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        fieldType));
                if (isObject){
                    if (fieldInfo.isArray()){
                        il.insert(instructionFactory.createCheckCast(new ObjectType(fieldInfo.getSignature())));
                    }else{
                        il.insert(instructionFactory.createCheckCast(new ObjectType(fieldInfo.getReturnType())));
                    }
                    il.insert(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            "replacingObjectField",
                            Type.OBJECT ,
                            new Type[]{PC_OBJECT_TYPE,Type.INT},
                            Constants.INVOKEINTERFACE));
                } else {
                    il.insert(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            stateManagerReplaceField,
                            fieldType ,
                            new Type[]{PC_OBJECT_TYPE,Type.INT},
                            Constants.INVOKEINTERFACE));
                }
                il.insert(new ILOAD(1));
                il.insert(new ALOAD(0));
                il.insert(instructionFactory.createGetField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoStateManager",
                        SM_OBJECT_TYPE));
                il.insert(new ALOAD(0));
                InstructionHandle switchHandel = il.insert(new ALOAD(0));
                TableSwitchHelper tsh = new TableSwitchHelper();
                tsh.match = fieldNum;
                tsh.target = switchHandel;
                switchList.add(tsh);
            }
            Iterator sIter = switchList.iterator();
            int count = 0;
            while (sIter.hasNext()){
                TableSwitchHelper tsh = (TableSwitchHelper)sIter.next();
                match[count] = tsh.match;
                targets[count] = tsh.target;
                count ++;
            }

            il.insert(new TABLESWITCH(match,targets,defaultHandle));
            InstructionHandle relativeFieldFromHandle = il.insert(new ILOAD(2));
            il.insert(new ISTORE(2));
            il.insert(new ISUB());
            il.insert(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    "jdoInheritedFieldCount",
                    Type.INT));
            il.insert(new ILOAD(1));
            methodGen.addLocalVariable("relativeField",Type.INT,2,relativeFieldFromHandle,returnHandel);
        } else if (classInfo.getPersistenceCapableSuperclass() != null){
          il.append(new ILOAD(1));
          il.append(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    "jdoInheritedFieldCount",
                    Type.INT));
          il.append(new ISUB());
          il.append(new ISTORE(2));
          InstructionHandle relativeField_Start = il.append(new ILOAD(2));
      IFGE ifge = new IFGE(null);
      il.append(ifge);
      il.append(new ALOAD(0));
      il.append(new ILOAD(1));

      il.append(instructionFactory.createInvoke(
                classInfo.getPersistenceCapableSuperclass(),
                "jdoReplaceField",
                Type.VOID ,
                new Type[]{Type.INT},
                Constants.INVOKESPECIAL));
      GOTO aGoto = new GOTO(null);
      il.append(aGoto);
      InstructionHandle newHandel = il.append(instructionFactory.createNew("java.lang.IllegalArgumentException"));
      ifge.setTarget(newHandel);
      il.append(new DUP());
      il.append(new PUSH(constantPoolGen,"fieldNumber"));
      il.append(instructionFactory.createInvoke(
                "java.lang.IllegalArgumentException",
                "<init>",
                Type.VOID ,
                new Type[]{Type.STRING},
                Constants.INVOKESPECIAL));
      il.append(new ATHROW());
      il.append(new RETURN());
      aGoto.setTarget(il.getEnd());

      methodGen.addLocalVariable("relativeField",Type.INT,2,relativeField_Start,il.getEnd());
        } else {
          il.append(new RETURN());
        }

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }





    private void addFieldGetters(){
        Iterator fieldIter = fieldSet.iterator();
        int fieldNum = 0;

        while (fieldIter.hasNext()){
            FieldInfo fieldInfo = (FieldInfo)fieldIter.next();
            int acc = Constants.ACC_STATIC  |
                    (fieldInfo.isPrivate() ? Constants.ACC_PRIVATE : (short)0) |
                    (fieldInfo.isProtected() ? Constants.ACC_PROTECTED : (short)0) |
                    (fieldInfo.isPublic() ? Constants.ACC_PUBLIC : (short)0);
            Type returnType = fieldInfo.getType();
            ReturnInstruction returnInstruction;
            String stateManagerGetField = null;
            boolean isObject = false;
            if (typeToGetField.containsKey(returnType)){
                stateManagerGetField = (String)typeToGetField.get(returnType);
                returnInstruction = (ReturnInstruction)typeToReturnType.get(returnType);
                isObject = false;
            } else {
                stateManagerGetField = "getObjectField";
                returnInstruction = new ARETURN();
                isObject = true;
            }

            InstructionList il = new InstructionList();

            MethodGen methodGen = new MethodGen(
                    acc,
                    returnType,
                    new Type[]{new ObjectType(classGen.getClassName())},
                    new String[]{"x"},
                    fieldInfo.getJdoGetName(),
                    classGen.getClassName(),
                    il,
                    constantPoolGen);


            if (fieldInfo.getFlag() == CHECK_READ_WRITE ){// this field is in the default fetch group
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoFlags",
                        Type.BYTE));
                IFGT ifgt = new IFGT(null);
                il.append(ifgt);
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
                InstructionHandle ifgtHandel = il.append(new ALOAD(0));
                ifgt.setTarget(ifgtHandel);
                il.append(instructionFactory.createGetField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoStateManager",
                        SM_OBJECT_TYPE));
                il.append(new ASTORE(1));
                InstructionHandle smHandle = il.append(new ALOAD(1));
                IFNULL ifnull = new IFNULL(null);                        // null to aload_0 58
                il.append(ifnull);
                il.append(new ALOAD(1));
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        "jdoInheritedFieldCount",
                        Type.INT));
                il.append(new PUSH(constantPoolGen, fieldNum));
                il.append(new IADD());
                il.append(instructionFactory.createInvoke(
                        STATE_MANAGER,
                        "isLoaded",
                        Type.BOOLEAN ,
                        new Type[]{PC_OBJECT_TYPE,Type.INT},
                        Constants.INVOKEINTERFACE));
                IFEQ ifeq = new IFEQ(null);
                il.append(ifeq);                                          // null to aload_1 41
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
                InstructionHandle ifeqHandel = il.append(new ALOAD(1));
                ifeq.setTarget(ifeqHandel);
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        "jdoInheritedFieldCount",
                        Type.INT));
                il.append(new PUSH(constantPoolGen, fieldNum));
                il.append(new IADD());
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                if (isObject){//if there is a object cast it
                    il.append(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            stateManagerGetField,
                            Type.OBJECT ,
                            new Type[]{
                                PC_OBJECT_TYPE,
                                Type.INT,
                                Type.OBJECT},
                            Constants.INVOKEINTERFACE));
                    il.append(instructionFactory.createCheckCast((ReferenceType)fieldInfo.getType()));
                } else {
                    il.append(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            stateManagerGetField,
                            returnType ,
                            new Type[]{
                                PC_OBJECT_TYPE,
                                Type.INT,
                                returnType},
                            Constants.INVOKEINTERFACE));
                }
                il.append(returnInstruction);
                InstructionHandle ifNullHandle = il.append(new ALOAD(0));
                ifnull.setTarget(ifNullHandle);
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
                methodGen.addLocalVariable("sm",SM_OBJECT_TYPE ,1,smHandle,il.getEnd());

            } else if (fieldInfo.getFlag() == MEDIATE_READ_WRITE){

                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoStateManager",
                        SM_OBJECT_TYPE));
                il.append(new ASTORE(1));
                InstructionHandle smHandle = il.append(new ALOAD(1));
                IFNULL ifnull = new IFNULL(null);                        // null to aload_0 58
                il.append(ifnull);
                il.append(new ALOAD(1));
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        "jdoInheritedFieldCount",
                        Type.INT));
                il.append(new PUSH(constantPoolGen, fieldNum));
                il.append(new IADD());
                il.append(instructionFactory.createInvoke(
                        STATE_MANAGER,
                        "isLoaded",
                        Type.BOOLEAN ,
                        new Type[]{PC_OBJECT_TYPE,Type.INT},
                        Constants.INVOKEINTERFACE));
                IFEQ ifeq = new IFEQ(null);
                il.append(ifeq);                                          // null to aload_1 41
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
                InstructionHandle ifeqHandel = il.append(new ALOAD(1));
                ifeq.setTarget(ifeqHandel);
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        "jdoInheritedFieldCount",
                        Type.INT));
                il.append(new PUSH(constantPoolGen, fieldNum));
                il.append(new IADD());
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                if (isObject){//if there is a object cast it
                    il.append(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            stateManagerGetField,
                            Type.OBJECT ,
                            new Type[]{
                                PC_OBJECT_TYPE,
                                Type.INT,
                                Type.OBJECT},
                            Constants.INVOKEINTERFACE));
                    il.append(instructionFactory.createCheckCast((ReferenceType)fieldInfo.getType()));
                } else {
                    il.append(instructionFactory.createInvoke(
                            STATE_MANAGER,
                            stateManagerGetField,
                            returnType ,
                            new Type[]{
                                PC_OBJECT_TYPE,
                                Type.INT,
                                returnType},
                            Constants.INVOKEINTERFACE));
                }
                il.append(returnInstruction);
                InstructionHandle ifNullHandle = il.append(new ALOAD(0));
                ifnull.setTarget(ifNullHandle);
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
                methodGen.addLocalVariable("sm",SM_OBJECT_TYPE,1,smHandle,il.getEnd());


            } else {//no mediation
                if (fieldInfo.primaryKey() &&
                        (classInfo.getIdentityType() == MDStatics.IDENTITY_TYPE_APPLICATION) &&
                        classInfo.isKeyGen()){

                    il.append(new ALOAD(0));
                    il.append(instructionFactory.createGetField(classGen.getClassName(),
                            "jdoStateManager",
                            new ObjectType("javax.jdo.spi.StateManager")));
                    il.append(new INSTANCEOF(constantPoolGen.addClass(VERSANT_STATE_MANAGER)));
                    IFEQ ifeq = new IFEQ(null);
                    il.append(ifeq);          //25
                    il.append(new ALOAD(0));
                    il.append(instructionFactory.createGetField(classGen.getClassName(),
                            "jdoStateManager",
                            new ObjectType("javax.jdo.spi.StateManager")));
                    il.append(instructionFactory.createCheckCast(new ObjectType(VERSANT_STATE_MANAGER)));
                    il.append(instructionFactory.createGetStatic(classGen.getClassName(),
                            "jdoInheritedFieldCount",
                            Type.INT));
                    il.append(new PUSH(constantPoolGen, fieldInfo.getFieldNo()));
                    il.append(new IADD());
                    il.append(instructionFactory.createInvoke(VERSANT_STATE_MANAGER,
                            "fillNewAppPKField",
                            Type.VOID,
                            new Type[]{Type.INT},
                            Constants.INVOKEINTERFACE));
                    InstructionHandle nopHandle = il.append(new NOP());
                    ifeq.setTarget(nopHandle);
                }
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        returnType));
                il.append(returnInstruction);
            }
            methodGen.removeNOPs();
            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
            fieldNum ++;

        }

    }

    private void makeSynthetic(FieldGenOrMethodGen gen) {
        gen.addAttribute(new Synthetic(synthetic, 0, null, gen.getConstantPool().getConstantPool()));
    }


    private void addFieldSetters(){
        Iterator fieldIter = fieldSet.iterator();
        int fieldNum = 0;

        while (fieldIter.hasNext()){
            FieldInfo fieldInfo = (FieldInfo)fieldIter.next();

            int acc = Constants.ACC_STATIC  |
                    (fieldInfo.isPrivate() ? Constants.ACC_PRIVATE : (short)0) |
                    (fieldInfo.isProtected() ? Constants.ACC_PROTECTED : (short)0) |
                    (fieldInfo.isPublic() ? Constants.ACC_PUBLIC : (short)0);

            Type fieldType = fieldInfo.getType();
            boolean isObject = false;
            String stateManagerSetField = null;
            if (typeToSetField.containsKey(fieldType)){
                stateManagerSetField = (String)typeToSetField.get(fieldType);
                isObject = false;
            } else {
                stateManagerSetField = "setObjectField";
                isObject = true;
            }

            InstructionList il = new InstructionList();
            MethodGen methodGen = new MethodGen(
                    acc,
                    Type.VOID,
                    new Type[]{new ObjectType(classGen.getClassName()),
                               fieldType},
                    new String[]{"x",
                                 "newValue"},
                    fieldInfo.getJdoSetName(),
                    classGen.getClassName(),
                    il,
                    constantPoolGen);

            int flags = fieldInfo.getFlag();
            boolean isLorD = false;
            if (fieldType.equals(Type.LONG) || fieldType.equals(Type.DOUBLE)) isLorD = true;
            IFNE ifne = new IFNE(null);
            if (flags == CHECK_READ_WRITE || flags == CHECK_WRITE ){// this field is in the default fetch group or is transient transactional
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(
                        getTopPCSuperOrCurrentClassName(),
                        "jdoFlags",
                        Type.BYTE));

                il.append(ifne);         // 13
                il.append(new ALOAD(0));
                if (isObject){
                    il.append(new ALOAD(1));
                } else {
                    il.append((LoadInstruction)typeToLoadType.get(fieldType));
                }
                il.append(instructionFactory.createPutField(
                        classGen.getClassName(),
                        fieldInfo.getFieldName(),
                        fieldType));
                il.append(new RETURN());
            }
            InstructionHandle ifneHandel = il.append(new ALOAD(0));
            ifne.setTarget(ifneHandel);
            il.append(instructionFactory.createGetField(
                    getTopPCSuperOrCurrentClassName(),
                    "jdoStateManager",
                    SM_OBJECT_TYPE));
            il.append(new ASTORE((isLorD ? 3 : 2)));
            InstructionHandle smStartHandle = il.append(new ALOAD((isLorD ? 3 : 2)));
            IFNULL ifnull = new IFNULL(null);
            il.append(ifnull);
            il.append(new ALOAD((isLorD ? 3 : 2)));
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    "jdoInheritedFieldCount",
                    Type.INT));
            il.append(new PUSH(constantPoolGen, fieldNum));
            il.append(new IADD());
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(
                    classGen.getClassName(),
                    fieldInfo.getFieldName(),
                    fieldType));
            if (isObject){//if there is a object call it with Object's
                il.append(new ALOAD(1));
                il.append(instructionFactory.createInvoke(
                        STATE_MANAGER,
                        stateManagerSetField,
                        Type.VOID ,
                        new Type[]{PC_OBJECT_TYPE,
                                   Type.INT,
                                   Type.OBJECT,
                                   Type.OBJECT},
                        Constants.INVOKEINTERFACE));
            } else {
                il.append((LoadInstruction)typeToLoadType.get(fieldType));
                il.append(instructionFactory.createInvoke(
                        STATE_MANAGER,
                        stateManagerSetField,
                        Type.VOID,
                        new Type[]{PC_OBJECT_TYPE,
                                   Type.INT,
                                   fieldType,
                                   fieldType},
                        Constants.INVOKEINTERFACE));
            }
            GOTO aGoto = new GOTO(null);
            il.append(aGoto);
            InstructionHandle ifnullHandle = il.append(new ALOAD(0));
            ifnull.setTarget(ifnullHandle);
            if (isObject){//if there is a object call it with Object's
                il.append(new ALOAD(1));
            } else {
                il.append((LoadInstruction)typeToLoadType.get(fieldType));
            }
            il.append(instructionFactory.createPutField(
                    classGen.getClassName(),
                    fieldInfo.getFieldName(),
                    fieldType));
            InstructionHandle lastHandle = il.append(new RETURN());
            aGoto.setTarget(lastHandle);


            methodGen.addLocalVariable(
                    "sm",
                    SM_OBJECT_TYPE,
                    (isLorD ? 3 : 2),
                    smStartHandle,
                    il.getEnd());

            makeSynthetic(methodGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();
            classGen.addMethod(methodGen.getMethod());
            il.dispose();
            fieldNum ++;

        }

    }


    private void addJdoGetManagedFieldCount(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_STATIC | Constants.ACC_PROTECTED,
                Type.INT,
                null,
                null,
                "jdoGetManagedFieldCount",
                classGen.getClassName(),
                il,
                constantPoolGen);
        il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                "jdoInheritedFieldCount",
                Type.INT));
        il.append(new PUSH(constantPoolGen, fieldSet.size()));
        il.append(new IADD());
        il.append(new IRETURN());

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }



    private void addJdoInheritedFieldCount(){
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_PRIVATE | Constants.ACC_STATIC ,//| NEW Constants.ACC_FINAL,
                Type.INT,
                "jdoInheritedFieldCount",
                constantPoolGen);
        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();
        InstructionHandle initialReturnHandle = il.getEnd();
        InstructionHandle nopTarget = il.append(new NOP());
        if (classInfo.getPersistenceCapableSuperclass() == null){
            il.append(new ICONST(0));
        } else {
          il.append(instructionFactory.createInvoke(
                    classInfo.getPersistenceCapableSuperclass(),
                    "jdoGetManagedFieldCount",
                    Type.INT,
                    new Type[]{},
                    Constants.INVOKESTATIC));
        }
        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                "jdoInheritedFieldCount",
                Type.INT));
        il.append(new RETURN());
        try{
//            System.out.println("initialReturnHandle that was deleted = " + initialReturnHandle);
            il.delete(initialReturnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }

        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m,methodGen.getMethod());
        il.dispose();
    }

    private void addJdoFieldTypes(){
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_PRIVATE | Constants.ACC_STATIC ,//| NEW Constants.ACC_FINAL,
                new ArrayType("java.lang.Class",1),
                "jdoFieldTypes",
                constantPoolGen);
        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();

        InstructionHandle initialReturnHandle = il.getEnd();
        InstructionHandle nopTarget = il.append(new NOP());
        il.append(new PUSH(constantPoolGen, fieldSet.size()));
        il.append(new ANEWARRAY(constantPoolGen.addClass(new ObjectType("java.lang.Class"))));
        il.append(new DUP());
        Iterator iter = fieldSet.iterator();
        int push = 0;
        while (iter.hasNext()){
            FieldInfo field = (FieldInfo)iter.next();
            if(field.isPrimative()){
                il.append(new PUSH(constantPoolGen, push));
                il.append(instructionFactory.createGetStatic(
                        field.getPrimativeTypeObject(),
                        "TYPE",
                        new ObjectType("java.lang.Class")));
                il.append(new AASTORE());
                il.append(new DUP());
            } else {
                InstructionList tempIl = new InstructionList();
                String returnType = field.getReturnType();
                String fieldName = getSetClass$Field(field);
                tempIl.insert(new DUP());
                InstructionHandle gotoAASTORE = tempIl.insert(new AASTORE());
                InstructionHandle gotoGetStatic = tempIl.insert(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        fieldName,
                        new ObjectType("java.lang.Class")));
                tempIl.insert(new GOTO(gotoAASTORE));
                tempIl.insert(instructionFactory.createPutStatic(
                        classGen.getClassName(),
                        fieldName,
                        new ObjectType("java.lang.Class")));
                tempIl.insert(new DUP());
                tempIl.insert(instructionFactory.createInvoke(
                        classGen.getClassName(),
                        "class$",
                        new ObjectType("java.lang.Class"),
                        new Type[]{new ObjectType("java.lang.String")},
                        Constants.INVOKESTATIC));
                if (field.isArray()){
                    tempIl.insert(new PUSH(constantPoolGen,field.getSignature().replace('/','.')));
                } else {
                    tempIl.insert(new PUSH(constantPoolGen,returnType));
                }

                tempIl.insert(new IFNONNULL(gotoGetStatic));
                tempIl.insert(instructionFactory.createGetStatic(
                        classGen.getClassName(),
                        fieldName,
                        new ObjectType("java.lang.Class")));
                tempIl.insert(new PUSH(constantPoolGen, push));

                il.append(tempIl);
            }
            push++;
        }
        try{
            il.delete(il.getEnd());
        } catch (TargetLostException e){//there should never be target for this instruction (DUP)
            e.printStackTrace();
        }

        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                "jdoFieldTypes",
                new ArrayType(new ObjectType("java.lang.Class"),1)));
        il.append(new RETURN());
        try{
            il.delete(initialReturnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }
        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m,methodGen.getMethod());
        il.dispose();
    }


    private void addJdoFieldFlags(){
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_PRIVATE | Constants.ACC_STATIC ,//| NEW Constants.ACC_FINAL,
                new ArrayType(Type.BYTE,1),
                "jdoFieldFlags",
                constantPoolGen);

        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();

        InstructionHandle initialReturnHandle = il.getEnd();
        InstructionHandle nopTarget = il.append(new NOP());
        il.append(new PUSH(constantPoolGen, fieldSet.size()));
        il.append(new NEWARRAY((Type.BYTE).getType()));
        Iterator iter = fieldSet.iterator();
        int push = 0;
        while (iter.hasNext()){
            FieldInfo field = (FieldInfo)iter.next();
            il.append(new DUP());
            il.append(new PUSH(constantPoolGen, push));
            il.append(new PUSH(constantPoolGen, field.getFlag()));
            il.append(new BASTORE());
            push++;
        }
        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                "jdoFieldFlags",
                new ArrayType(Type.BYTE,1)));
        il.append(new RETURN());
        try{
            il.delete(initialReturnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }
        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m,methodGen.getMethod());
        il.dispose();

    }




    private void addInterrogatives(){
        if (classInfo.getTopPCSuperClass() == null){
            setInterrogative("jdoIsPersistent","isPersistent");
            setInterrogative("jdoIsTransactional","isTransactional");
            setInterrogative("jdoIsNew","isNew");
            setInterrogative("jdoIsDirty","isDirty");
            setInterrogative("jdoIsDeleted","isDeleted");
            setJdoGetPersistanceManager();
            setJdoMakeDirty();
        }
    }

    /**
     * Add method
     * public PersistenceManager jdoGetPersistenceManager(){
     *     return jdoStateManager == null ? null : jdoStateManager.getPersistenceManager(this);
     * }
     */
    private void setJdoGetPersistanceManager(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC ,
                new ObjectType("javax.jdo.PersistenceManager"),
                null,
                null,
                "jdoGetPersistenceManager",
                classGen.getClassName(),
                il,
                constantPoolGen);

        InstructionHandle ireturnHandle = il.insert(new ARETURN());
        il.insert(instructionFactory.createInvoke(
                STATE_MANAGER,
                "getPersistenceManager",
                new ObjectType("javax.jdo.PersistenceManager"),
                new Type[]{PC_OBJECT_TYPE},
                Constants.INVOKEINTERFACE));
        il.insert(new ALOAD(0));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        InstructionHandle ifNonNullHandle = il.insert(new ALOAD(0));
        il.insert(new GOTO(ireturnHandle));
        il.insert(new ACONST_NULL());
        il.insert(new IFNONNULL(ifNonNullHandle));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        il.insert(new ALOAD(0));

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }
    /**
     * Add method
     *
     *  public void jdoMakeDirty(String fieldName){
     *      if(jdoStateManager==null) return;
     *      jdoStateManager.makeDirty(this, fieldName);
     *  }
     *
     */
    private void setJdoMakeDirty(){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC ,
                Type.VOID,
                new Type[]{Type.STRING},
                new String[]{"fieldName"},
                "jdoMakeDirty",
                classGen.getClassName(),
                il,
                constantPoolGen);
        il.insert(new RETURN());
        il.insert(instructionFactory.createInvoke(
                STATE_MANAGER,
                "makeDirty",
                Type.VOID,
                new Type[]{PC_OBJECT_TYPE, Type.STRING},
                Constants.INVOKEINTERFACE));
        il.insert(new ALOAD(1));
        il.insert(new ALOAD(0));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        InstructionHandle ifNonNullHandle = il.insert(new ALOAD(0));
        il.insert(new RETURN());
        il.insert(new IFNONNULL(ifNonNullHandle));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        il.insert(new ALOAD(0));

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addJdoFieldNames(){
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_PRIVATE | Constants.ACC_STATIC ,// | NEW Constants.ACC_FINAL,
                new ArrayType(Type.STRING,1),
                "jdoFieldNames",
                constantPoolGen);
        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();

        InstructionHandle initialReturnHandle = il.getEnd();

        InstructionHandle nopTarget = il.append(new NOP());
        il.append(new PUSH(constantPoolGen, fieldSet.size()));
        il.append(new ANEWARRAY(constantPoolGen.addClass(Type.STRING)));

        Iterator iter = fieldSet.iterator();
        int push = 0;
        while (iter.hasNext()){
            FieldInfo field = (FieldInfo)iter.next();
            il.append(new DUP());
            il.append(new PUSH(constantPoolGen, push));
            il.append(new PUSH(constantPoolGen,field.getFieldName()));
            il.append(new AASTORE());
            push++;
        }
        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                "jdoFieldNames",
                new ArrayType(Type.STRING,1)));
        il.append(new RETURN());
        try{
//            System.out.println("initialReturnHandle that was deleted = " + initialReturnHandle);
            il.delete(initialReturnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }

        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m,methodGen.getMethod());
        il.dispose();
    }


    private void setInterrogative(String methodName,String callingMethodName){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_PUBLIC ,
                Type.BOOLEAN,
                null,
                null,
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);
        InstructionHandle ireturnHandle = il.insert(new IRETURN());
        il.insert(instructionFactory.createInvoke(
                STATE_MANAGER,
                callingMethodName,
                Type.BOOLEAN,
                new Type[]{PC_OBJECT_TYPE},
                Constants.INVOKEINTERFACE));
        il.insert(new ALOAD(0));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        InstructionHandle ifNonNullHandle = il.insert(new ALOAD(0));
        il.insert(new GOTO(ireturnHandle));
        il.insert(new ICONST(0));
        il.insert(new IFNONNULL(ifNonNullHandle));
        il.insert(instructionFactory.createGetField(
                getTopPCSuperOrCurrentClassName(),
                "jdoStateManager",
                SM_OBJECT_TYPE));
        il.insert(new ALOAD(0));

//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }

    private void addSerialVersionUID(){
        if (!hasSerialVersionUID()){
            FieldGen fieldGen = new FieldGen(
                    Constants.ACC_PRIVATE | Constants.ACC_STATIC  | Constants.ACC_FINAL,
                    Type.LONG,
                    "serialVersionUID",
                    constantPoolGen);
            fieldGen.setInitValue(currentSerialVersionUID);
            makeSynthetic(fieldGen);
            classGen.addField(fieldGen.getField());

            if (javaVersion >= JAVA_1_4){
                /**
                 * todo add serialVersionUID static constructor to for jdk 1.4
                 */
            }
        }
    }
    /**
     * Check if current class has a serialVersionUID.
     *
     * @return true if it does have a serialVersionUID, else false.
     */
    private boolean hasSerialVersionUID(){
        Field [] fields = classGen.getFields();
        for(int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            if (f.getName().equals("serialVersionUID")){
                return true;
            }
        }
        return false;
    }

    /**
     * Addes a field jdoPersistenceCapableSuperclass and initializes it to null if there
     * is no persistence capable superclass else it initializes it.
     *
     */
    private void addJdoPersistenceCapableSuperclass(){
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_PRIVATE | Constants.ACC_STATIC ,//| NEW Constants.ACC_FINAL,
                new ObjectType("java.lang.Class"),
                "jdoPersistenceCapableSuperclass",
                constantPoolGen);
        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        Method m = getStaticConstructor();
        MethodGen methodGen = new MethodGen(
                m,
                classGen.getClassName(),
                constantPoolGen);
        InstructionList il = methodGen.getInstructionList();
        InstructionHandle initialReturnHandle = il.getEnd();
        InstructionHandle nopTarget = il.append(new NOP());
        if (classInfo.getPersistenceCapableSuperclass() == null){
            il.append(InstructionConstants.ACONST_NULL);
            il.append(instructionFactory.createPutStatic(
                    classGen.getClassName(),
                    "jdoPersistenceCapableSuperclass",
                    new ObjectType("java.lang.Class")));
        } else {

            String className = classInfo.getPersistenceCapableSuperclass();
            String fieldName = getSetClass$Field(className);

            il.append(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    fieldName,
                    new ObjectType("java.lang.Class")));
            IFNONNULL ifNonNull = new IFNONNULL(null);
            il.append(ifNonNull);
            il.append(new PUSH(constantPoolGen,className));
            il.append(instructionFactory.createInvoke(
                    classGen.getClassName(),
                    "class$",
                    new ObjectType("java.lang.Class"),
                    new Type[]{new ObjectType("java.lang.String")},
                    Constants.INVOKESTATIC));
            il.append(new DUP());
            il.append(instructionFactory.createPutStatic(
                    classGen.getClassName(),
                    fieldName,
                    new ObjectType("java.lang.Class")));
            GOTO gotoInst = new GOTO(null);
            il.append(gotoInst);
            InstructionHandle ifNonNullHandle = il.append(instructionFactory.createGetStatic(
                    classGen.getClassName(),
                    fieldName,
                    new ObjectType("java.lang.Class")));
            ifNonNull.setTarget(ifNonNullHandle);
            InstructionHandle gotoHandle = il.append(instructionFactory.createPutStatic(
                    classGen.getClassName(),
                    "jdoPersistenceCapableSuperclass",
                    new ObjectType("java.lang.Class")));
            gotoInst.setTarget(gotoHandle);
        }
        il.append(new RETURN());
        try{
            il.delete(initialReturnHandle);
        } catch (TargetLostException e){
            InstructionHandle[] targets = e.getTargets();
            for (int i = 0; i < targets.length ; i++){
                InstructionTargeter[] targeters = targets[i].getTargeters();
                for (int j = 0; j < targeters.length ; j++){
                    targeters[j].updateTarget(targets[i], nopTarget);
                }
            }
        }
        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.replaceMethod(m,methodGen.getMethod());
        il.dispose();
    }
    /**
     * All class variables i.e. String.class has a static variable called
     * class$java$lang$String of type java.lang.Class, this method creates it if
     * it does not exist.
     *
     * @param  className
     * @return String fieldName i.e. class$java$lang$String
     */
    private String getSetClass$Field(String className){
        String fullClassName = "class."+className;
        String fieldName = fullClassName.replace('.','$');
        Field [] fields = classGen.getFields();
        for(int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            if (f.getName().equals(fieldName)){
                return fieldName;
            }
        }
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_STATIC,
                new ObjectType("java.lang.Class"),
                fieldName,
                constantPoolGen);
        classGen.addField(fieldGen.getField());
        return fieldName;

    }
    /**
     * All class variables i.e. String.class has a static variable called
     * class$java$lang$String of type java.lang.Class, this method creates it if
     * it does not exist.
     *
     * @param field
     * @return String fieldName i.e. class$java$lang$String
     */
    private String getSetClass$Field(FieldInfo field){
        String fullClassName = null;
        if (field.isArray()){
            fullClassName = ("array" + field.getSignature()).replace('/', '$');
            fullClassName = fullClassName.replace('[', '$');
            fullClassName = (fullClassName.replace(';', ' ')).trim();
        }else{
            fullClassName = "class."+field.getReturnType();
        }
        String fieldName = fullClassName.replace('.','$');
        Field [] fields = classGen.getFields();
        for(int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            if (f.getName().equals(fieldName)){
                return fieldName;
            }
        }
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_STATIC,
                new ObjectType("java.lang.Class"),
                fieldName,
                constantPoolGen);
        makeSynthetic(fieldGen);
        classGen.addField(fieldGen.getField());
        return fieldName;

    }
    /**
     * Check if current class implements PersistenceCapable.
     *
     * @return true if it does implement PersistenceCapable else false.
     */
    private boolean implementsPC(){
        String[] interfaceNames = classGen.getInterfaceNames();
        for(int i = 0; i < interfaceNames.length; i++) {
            if (interfaceNames[i].equals(PERSISTENCE_CAPABLE)){
                return true;
            }
        }
        return false;
    }
    /**
     * All class variables i.e. String.class has a static class$ method that check if the class
     * exists by doing a class.forname() on the class and throws a NoClassDefFoundError error,
     * if the class does not exists
     *
     */
    private void setClass$(){
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];

            if (m.getName().equals("class$") &&
                    "(Ljava/lang/String;)Ljava/lang/Class;".equals(m.getSignature())){
                return;
            }
        }
        // there is no class$ method so make one
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_STATIC,
                new ObjectType("java.lang.Class"),
                new Type[]{new ObjectType("java.lang.String")},
                new String[]{"x0"},
                "class$",
                classGen.getClassName(),
                il,
                constantPoolGen);

        InstructionHandle tryStart = il.append(new ALOAD(0));
        il.append(instructionFactory.createInvoke(
                "java.lang.Class",
                "forName",
                new ObjectType("java.lang.Class"),
                new Type[]{new ObjectType("java.lang.String")},
                Constants.INVOKESTATIC));
        InstructionHandle tryEnd = il.append(new ARETURN());
        InstructionHandle handler = il.append(new ASTORE(1));
        InstructionHandle varStart = il.append(instructionFactory.createNew("java.lang.NoClassDefFoundError"));
        il.append(new DUP());
        il.append(new ALOAD(1));
        il.append(instructionFactory.createInvoke(
                "java.lang.Throwable",
                "getMessage",
                new ObjectType("java.lang.String"),
                new Type[]{},
                Constants.INVOKEVIRTUAL));
        il.append(instructionFactory.createInvoke(
                "java.lang.NoClassDefFoundError",
                "<init>",
                Type.VOID,
                new Type[]{new ObjectType("java.lang.String")},
                Constants.INVOKESPECIAL));
        InstructionHandle varEnd = il.append(new ATHROW());
        methodGen.addLocalVariable("x1",new ObjectType("java.lang.ClassNotFoundException"),varStart,varEnd);
        methodGen.addExceptionHandler(tryStart,tryEnd,handler,new ObjectType("java.lang.ClassNotFoundException"));
        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        Method class$Method = methodGen.getMethod();
        classGen.addMethod(class$Method);
        il.dispose();
        return ;

    }

    private void rewriteStaticConstructor(){
        Method[] methods = classGen.getMethods();
        for (int k = 0; k < methods.length; k++) {
            Method m = methods[k];
            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()) {
                continue;
            }
            if (m.getName().equals("<clinit>")) {//is static constructor
                boolean hasChanges = false;
                MethodGen mg = new MethodGen(m, classGen.getClassName(), constantPoolGen);

                // get the code in form of an InstructionList object
                InstructionList il = mg.getInstructionList();
                Instruction ins;
                InstructionHandle ih = il.getStart();
                while (ih != null) {
                    ins = ih.getInstruction();
                    if (ins instanceof LDC) {
                        LDC ldc = (LDC) ins;
                        Constant c = constantPoolGen.getConstantPool().getConstant(ldc.getIndex());
                        if (c.getTag() == Constants.CONSTANT_Class) {
                            hasChanges = true;
                            String name = constantPoolGen.getConstantPool().getConstantString(ldc.getIndex(), Constants.CONSTANT_Class);

                            if (!name.startsWith("[")) {
                                name = "L" + name + ";";
                            }

                            Type type = Type.getType(name);
                            InstructionList tempIl = pushDotClass(type);
                            InstructionHandle startTarget = tempIl.getStart();
                            InstructionHandle newTarget = tempIl.getEnd();
                            il.append(ih, tempIl);
                            try {
                                il.delete(ih);
                            } catch (TargetLostException e) {
                                InstructionHandle[] targets = e.getTargets();
                                for (int i = 0; i < targets.length; i++) {
                                    InstructionTargeter[] targeters = targets[i].getTargeters();
                                    for (int j = 0; j < targeters.length; j++) {
                                        targeters[j].updateTarget(targets[i], newTarget);
                                    }
                                }
                            }
                            il.setPositions();
                            il.update();
                            // Fix line numbers
                            LineNumberGen[] numbersGen = mg.getLineNumbers();
                            if (numbersGen != null){
                                for (int i = 0; i < numbersGen.length; i++) {
                                    LineNumberGen lineNumberGen = numbersGen[i];
                                    if (lineNumberGen.containsTarget(newTarget)){
                                        lineNumberGen.setInstruction(startTarget);
                                    }
                                }
                            }

                            ih = il.getStart();

                        }
                    }
                    ih = ih.getNext();
                }
                if (hasChanges){
                    il.setPositions();
                    il.update();
                    mg.removeNOPs();
                    mg.setMaxLocals();
                    mg.setMaxStack();
                    classGen.replaceMethod(m, mg.getMethod());
                }
            }
        }
    }
    /**
     * Returns the static constructor if it exists, else it creates it and then
     * returns it.
     *
     */
    private Method getStaticConstructor(){
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()){
                continue;
            }
            if (m.getName().equals("<clinit>")){//is static constructor
                return m;
            }
        }
        // there is no static constructor so make one
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(
                Constants.ACC_STATIC,
                Type.VOID,
                null,
                null,
                "<clinit>",
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new RETURN());
//        makeSynthetic(methodGen);
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        Method clMethod = methodGen.getMethod();
        classGen.addMethod(clMethod);
        il.dispose();
        return clMethod;

    }

    /**
     * Adds field jdoStateManager it does not need to be initializes.
     *
     */
    private void addJdoStateManager(){
        //this field only gets added to the least-derived persistence capable class.
        if (classInfo.getPersistenceCapableSuperclass() == null){
            FieldGen fieldGen = new FieldGen(
                    Constants.ACC_PROTECTED | Constants.ACC_TRANSIENT,
                    SM_OBJECT_TYPE,
                    "jdoStateManager",
                    constantPoolGen);
            makeSynthetic(fieldGen);
            classGen.addField(fieldGen.getField());
        }
    }
    /**
     * Adds field jdoFlags in the top most persistence capable super class and initializes
     * it to javax.jdo.spi.PersistenceCapable.READ_WRITE_OK.
     * The initialization needs to occur in all the constructors as it is with all class fields.
     *
     */
    private void addJdoFlags() {
        //this field only gets added to the least-derived persistence capable class.
        if (classInfo.getPersistenceCapableSuperclass() == null){
            FieldGen fieldGen = new FieldGen(
                    Constants.ACC_PROTECTED | Constants.ACC_TRANSIENT,
                    Type.BYTE,
                    "jdoFlags",
                    constantPoolGen);
            makeSynthetic(fieldGen);
            classGen.addField(fieldGen.getField());
            List constructors = getInitilizationConstructors();//very important to only get these constructors
            Iterator iter = constructors.iterator();
            while (iter.hasNext()){
                Method constructor = (Method)iter.next();
                MethodGen mg = new MethodGen(
                        constructor,
                        classInfo.getClassName(),
                        constantPoolGen);

                InstructionList il = mg.getInstructionList();
                // get the first instruction
                InstructionHandle ih = il.getStart();
                while (ih != null) {
                    Instruction ins = ih.getInstruction();

                    if (ins instanceof INVOKESPECIAL) {// found the INVOKESPECIAL call
                        InstructionList tmpIl = new InstructionList();
                        tmpIl.append(new ALOAD(0));
                        tmpIl.append(new ICONST(0));//javax.jdo.spi.PersistenceCapable.READ_WRITE_OK
                        tmpIl.append(instructionFactory.createPutField(classInfo.getClassName(),
                                "jdoFlags",
                                Type.BYTE));
                        il.append(ih, tmpIl);
                        il.setPositions();
                        il.update();

                        mg.setInstructionList(il);
                        mg.setMaxLocals();
                        mg.setMaxStack();
                        classGen.replaceMethod(constructor, mg.getMethod());
                        il.dispose();
                        break;
                    }
                    // next instruction
                    ih = ih.getNext();
                }
            }
        }
    }

    /**
     * Gets a list of all the constructors methods
     */
    private List getConstructors(){
        ArrayList constuctors = new ArrayList();
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()){
                continue;
            }
            if (m.getName().equals("<init>")){//is constructor
                constuctors.add(m);
            }
        }
        return constuctors;
    }
    /**
     * Sets a default constructor if it needs one or changes the default
     * constructor's scope if needed.
     */
    private void setDefaultConstructor(){
//        if (classGen.isAbstract())return;
        boolean setDefautConstructor = true;
        Method[] methods = classGen.getMethods();
        for(int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            // native and abstract methods don't have any code
            // so continue with next method
            if (m.isNative() || m.isAbstract()){
                continue;
            }

            if (m.getName().equals("<init>")){              //is constructor
                if (m.getSignature().equals("()V")){        //is no args constructor
//                  if (m.isPublic() || m.isProtected()){   //is public or protected
                    if (m.isPublic() ){
                        setDefautConstructor = false;       //there is a default constructor with the right access
                    }else {                                 //there is a default constructor but access is wrong
                        m.isPublic(true);
                      m.isProtected(false);                //change access to protected
                        m.isPrivate(false);                 //take away private access
                        setDefautConstructor = false;       //now there is a default constructor with the right access
                    }
                }
            }
        }
        if (setDefautConstructor){
            InstructionList il = new InstructionList();
            il.append(InstructionConstants.THIS); // Push `this'
            il.append(new INVOKESPECIAL(constantPoolGen.addMethodref(
                    classGen.getSuperclassName(),
                    "<init>",
                    "()V")));
            il.append(InstructionConstants.RETURN);

            MethodGen methodGen = new MethodGen(
                    Constants.ACC_PUBLIC, // todo this is not to spec it should be protected
                    Type.VOID,
                    Type.NO_ARGS,
                    null,
                    "<init>",
                    classGen.getClassName(),
                    il,
                    constantPoolGen);
            methodGen.setMaxLocals();
            methodGen.setMaxStack();

            classGen.addMethod(methodGen.getMethod());
            didWeAddADefaultConstructor = true;
//            classGen.addEmptyConstructor(Constants.ACC_PUBLIC);// todo this is not to spec it should be protected
            // If initialization of user-declared field are required use this method
            //createDefaultInitializationConstructor();
        }
    }

    /**
     * Gets a list of all the initilization constructors methods
     */
    private List getInitilizationConstructors(){
        ArrayList initConst = new ArrayList();
        List list = getConstructors();
        Iterator iter = list.iterator();
        while (iter.hasNext()){
            Method m = (Method)iter.next();

            MethodGen mg = new MethodGen(m, classGen.getClassName(), constantPoolGen);

            // get the code in form of an InstructionList object
            InstructionList il = mg.getInstructionList();

            // get the first instruction
            InstructionHandle ih = il.getStart();
            while (ih != null) {
                Instruction ins = ih.getInstruction();
                if (ins.getClass().getName().equals(invokeSpecial)) {
                    INVOKESPECIAL is = (INVOKESPECIAL) ins;
                    if (is.getClassName(constantPoolGen).equals(classGen.getSuperclassName()) &&
                            is.getMethodName(constantPoolGen).equals("<init>")) {
                        initConst.add(m);
                    }
                }
                // next instruction
                ih = ih.getNext();
            }
        }
        return initConst;
    }


    /**
     * this method is not needed yet.
     */
//    private void createDefaultInitializationConstructor(){
//        List constructors = getInitilizationConstructors();
//        Iterator iter = constructors.iterator();
//        boolean wasGen = false;
//        while (iter.hasNext()){
//            Method m = (Method)iter.next();
//            MethodGen mg = new MethodGen(m, classInfo.getClassName() ,constantPoolGen);
//            LineNumberGen[] lineNumberGen = mg.getLineNumbers();
//            int firstLine = 0;
//            int nextLine = 10000;
//            int nextOffSet = 0;
//            InstructionHandle fromIH = null;
//            for (int i = 0; i < lineNumberGen.length ; i++){
//                int sourceLine = lineNumberGen[i].getSourceLine();
//                if (lineNumberGen[i].getLineNumber().getStartPC() == 0){
//                    firstLine = lineNumberGen[i].getSourceLine();
//                }
//
//                if (sourceLine > firstLine && sourceLine < nextLine){
//                    if (lineNumberGen[i].getInstruction().getInstruction() instanceof RETURN) {
//                    } else {
//                        fromIH = lineNumberGen[i].getInstruction();
//                        nextLine = sourceLine;
//                        nextOffSet = lineNumberGen[i].getLineNumber().getStartPC();
//                    }
//                }
//            }
//
//            if (nextOffSet > 5){
//                InstructionList il = mg.getInstructionList();
//                InstructionHandle toIH = il.getEnd().getPrev();
//                try{
//                    if (!fromIH.equals(il.getEnd().getPrev())){
//                        il.delete(fromIH,il.getEnd().getPrev());
//                    }
//                } catch (TargetLostException e){
//                    InstructionHandle[] targets = e.getTargets();
//                    for (int i = 0; i < targets.length ; i++){
//                        InstructionTargeter[] targeters = targets[i].getTargeters();
//                        for (int j = 0; j < targeters.length ; j++){
//                            targeters[j].updateTarget(targets[i], il.getEnd());
//                        }
//                    }
//                }
//
//                MethodGen newCons = new MethodGen(  Constants.ACC_PROTECTED,
//                        Type.VOID,
//                        new Type[]{},
//                        null,
//                        "<init>",
//                        classInfo.getClassName(),
//                        il,
//                        constantPoolGen);
//                newCons.getMaxLocals();
//                newCons.getMaxStack();
//                classGen.addMethod(newCons.getMethod());
//                wasGen = true;
//                break;
//            }
//        }
//        if (!wasGen){
//            classGen.addEmptyConstructor(Constants.ACC_PROTECTED);
//        }
//    }




    /**
     * All class variables i.e. String.class has a static variable called
     * class$java$lang$String of type java.lang.Class, this method creates it if
     * it does not exist.
     *
     * @param type
     * @return String fieldName i.e. class$java$lang$String
     */
    private InstructionList pushDotClass(Type type) {
        InstructionList il = new InstructionList();
        String signature = type.getSignature();
        String fieldName = null;
        String tempFieldName = null;
        String loadName = null;

        if (signature.startsWith("[")) {
            tempFieldName = ("array" + signature).replace('/', '$');
            tempFieldName = tempFieldName.replace('[', '$');
            fieldName = (tempFieldName.replace(';', ' ')).trim();
            loadName = signature.replace('/', '.');
        } else {
            tempFieldName = ("class/" + signature).replace('/', '$');
            fieldName = (tempFieldName.replace(';', ' ')).trim();
            loadName = type.toString();
        }

        il.append(instructionFactory.createGetStatic(classGen.getClassName(), fieldName, new ObjectType("java.lang.Class")));
        IFNONNULL ifnonnull = new IFNONNULL(null);
        il.append(ifnonnull);
        il.append(new PUSH(constantPoolGen, loadName));
        il.append(instructionFactory.createInvoke(
                classGen.getClassName(),
                "class$",
                new ObjectType("java.lang.Class"),
                new Type[]{Type.STRING},
                Constants.INVOKESTATIC));
        il.append(new DUP());
        il.append(instructionFactory.createPutStatic(
                classGen.getClassName(),
                fieldName,
                new ObjectType("java.lang.Class")));
        GOTO aGoto = new GOTO(null);
        il.append(aGoto);
        InstructionHandle getStaticHandle = il.append(instructionFactory.createGetStatic(
                classGen.getClassName(),
                fieldName,
                new ObjectType("java.lang.Class")));
        ifnonnull.setTarget(getStaticHandle);
        InstructionHandle lastHandle = il.append(new NOP());
        aGoto.setTarget(lastHandle);

        setClass$();
        Field[] fields = classGen.getFields();
        for (int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            if (f.getName().equals(fieldName)) {
                return il;
            }
        }
        FieldGen fieldGen = new FieldGen(
                Constants.ACC_STATIC | Constants.ACC_PRIVATE,
                new ObjectType("java.lang.Class"),
                fieldName,
                constantPoolGen);
        classGen.addField(fieldGen.getField());
        return il;

    }



    /**
     * Compute the JVM signature for the class.
     */
    static String getSignature(Class clazz) {
        String type = null;
        if (clazz.isArray()) {
            Class cl = clazz;
            int dimensions = 0;
            while (cl.isArray()) {
                dimensions++;
                cl = cl.getComponentType();
            }
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < dimensions; i++) {
                sb.append("[");
            }
            sb.append(getSignature(cl));
            type = sb.toString();
        } else if (clazz.isPrimitive()) {
            if (clazz == Integer.TYPE) {
                type = "I";
            } else if (clazz == Byte.TYPE) {
                type = "B";
            } else if (clazz == Long.TYPE) {
                type = "J";
            } else if (clazz == Float.TYPE) {
                type = "F";
            } else if (clazz == Double.TYPE) {
                type = "D";
            } else if (clazz == Short.TYPE) {
                type = "S";
            } else if (clazz == Character.TYPE) {
                type = "C";
            } else if (clazz == Boolean.TYPE) {
                type = "Z";
            } else if (clazz == Void.TYPE) {
                type = "V";
            }
        } else {
            type = "L" + clazz.getName().replace('.', '/') + ";";
        }
        return type;
    }

    // all the detach suff goes here


    private void addIsDirtyInt(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.BOOLEAN,
                new Type[]{Type.INT},
                new String[]{"fieldNo"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        int num = getNumOfControlFields();
        if (num == 1) {
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    getDirtyFieldName(0),
                    Type.INT));
            il.append(new ICONST(1));
            il.append(new ILOAD(1));
            il.append(new ISHL());
            il.append(new IAND());
            IFNE ifne = new IFNE(null);
            il.append(ifne);
            il.append(new ICONST(0));
            il.append(new IRETURN());
            InstructionHandle handle = il.append(new ICONST(1));
            ifne.setTarget(handle);
            il.append(new IRETURN());

        } else {
            il.append(new ILOAD(1));
            for (int i = 0; i < num; i++) {
                il.append(new PUSH(constantPoolGen, ((32 * i) + 32)));
                IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
                il.append(if_icmpge);
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(classGen.getClassName(),
                        getDirtyFieldName(i),
                        Type.INT));
                il.append(new ICONST(1));
                il.append(new ILOAD(1));
                il.append(new ISHL());
                il.append(new IAND());
                IFEQ ifeq = new IFEQ(null);
                il.append(ifeq);
                il.append(new ICONST(1));
                GOTO aGoto = new GOTO(null);
                il.append(aGoto);
                InstructionHandle iconst0Handle = il.append(new ICONST(0));
                ifeq.setTarget(iconst0Handle);
                InstructionHandle gotoHandle = il.append(new IRETURN());
                aGoto.setTarget(gotoHandle);
                InstructionHandle iload1Handle = il.append(new ILOAD(1));
                if_icmpge.setTarget(iload1Handle);
            }
            // take last one and replace with ICONST_0
            InstructionHandle lastHandle = il.getEnd();
            InstructionHandle replaceHandle = il.append(new ICONST(0));
            try {
                il.delete(lastHandle);
            } catch (TargetLostException e) {
                InstructionHandle[] targets = e.getTargets();
                for (int i = 0; i < targets.length; i++) {
                    InstructionTargeter[] targeters = targets[i].getTargeters();
                    for (int j = 0; j < targeters.length; j++) {
                        targeters[j].updateTarget(targets[i], replaceHandle);
                    }
                }
            }
            il.append(new IRETURN());
        }

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addMakeDirtyInt(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.VOID,
                new Type[]{Type.INT},
                new String[]{"fieldNo"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        int num = getNumOfControlFields();
        if (num == 1) {
            il.append(new ALOAD(0));
            il.append(new DUP());
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    getDirtyFieldName(0),
                    Type.INT));

            il.append(new ICONST(1));
            il.append(new ILOAD(1));
            il.append(new ISHL());
            il.append(new IOR());
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    getDirtyFieldName(0),
                    Type.INT));
            il.append(new RETURN());
        } else {
            il.append(new ILOAD(1));
            for (int i = 0; i < num; i++) {
                il.append(new PUSH(constantPoolGen, ((32 * i) + 32)));
                IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
                il.append(if_icmpge);

                il.append(new ALOAD(0));
                il.append(new DUP());
                il.append(instructionFactory.createGetField(classGen.getClassName(),
                        getDirtyFieldName(i),
                        Type.INT));
                il.append(new ICONST(1));
                il.append(new ILOAD(1));
                il.append(new ISHL());
                il.append(new IOR());
                il.append(instructionFactory.createPutField(classGen.getClassName(),
                        getDirtyFieldName(i),
                        Type.INT));
                if (i != (num - 1)) {
                    il.append(new RETURN());
                    InstructionHandle iloadHandle = il.append(new ILOAD(1));
                    if_icmpge.setTarget(iloadHandle);
                } else {
                    InstructionHandle returnHandle = il.append(new RETURN());   // last return
                    if_icmpge.setTarget(returnHandle);
                }
            }

        }
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addMakeDirtyString(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC,
                Type.VOID,
                new Type[]{Type.STRING},
                new String[]{"fieldName"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        ArrayList list = new ArrayList(fieldSet);
        Collections.sort(list);
        Iterator iter = list.iterator();
        ArrayList gotos = new ArrayList();

        while (iter.hasNext()) {
            FieldInfo info = (FieldInfo) iter.next();
            String fieldname = info.getFieldName();
            int fieldNo = info.getFieldNo();

            il.append(new PUSH(constantPoolGen, fieldname));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke(
                    "java.lang.String",
                    "equals",
                    Type.BOOLEAN,
                    new Type[]{Type.OBJECT},
                    Constants.INVOKEVIRTUAL));
            IFEQ ifeq = new IFEQ(null);        //17
            il.append(ifeq);
            il.append(new ALOAD(0));
            il.append(new PUSH(constantPoolGen, fieldNo));
            il.append(instructionFactory.createInvoke(
                    classGen.getClassName(),
                    "versantMakeDirty",
                    Type.VOID,
                    new Type[]{Type.INT},
                    Constants.INVOKEVIRTUAL));
            GOTO aGoto = new GOTO(null);
            gotos.add(aGoto);
            il.append(aGoto);
            InstructionHandle nopHandle = il.append(new NOP());
            ifeq.setTarget(nopHandle);
        }
        // now we do the else part
        if (classInfo.getPersistenceCapableSuperclass() != null){
            il.append(new ALOAD(0));
            il.append(new ALOAD(1));
            il.append(instructionFactory.createInvoke(
                    classInfo.getPersistenceCapableSuperclass(),
                    "versantMakeDirty",
                    Type.VOID,
                    new Type[]{Type.STRING},
                    Constants.INVOKESPECIAL));
        } else {
           // todo throw exception or something
        }



        InstructionHandle lastHandle = il.append(new RETURN());
        for (Iterator iterator = gotos.iterator(); iterator.hasNext();) {
            GOTO aGoto = (GOTO) iterator.next();
            aGoto.setTarget(lastHandle);
        }
        methodGen.removeNOPs();
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }


    private void addIsDirty(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC , //| NEW Constants.ACC_FINAL,
                Type.BOOLEAN,
                new Type[]{},
                new String[]{},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        ArrayList list = new ArrayList();
        int num = getNumOfControlFields();
        for (int i = 0; i < num; i++) {
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    getDirtyFieldName(i),
                    Type.INT));
            IFNE ifne = new IFNE(null);
            list.add(ifne);
            il.append(ifne);
        }
        il.append(new ICONST(0));
        il.append(new IRETURN());
        InstructionHandle ifne_handle = il.append(new ICONST(1));
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            IFNE ifne = (IFNE) iter.next();
            ifne.setTarget(ifne_handle);
        }
        il.append(new IRETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addIsLoadedInt(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.BOOLEAN,
                new Type[]{Type.INT},
                new String[]{"fieldNo"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        int num = getNumOfControlFields();
        if (num == 1) {
            il.append(new ALOAD(0));
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    getLoadedFieldName(0),
                    Type.INT));
            il.append(new ICONST(1));
            il.append(new ILOAD(1));
            il.append(new ISHL());
            il.append(new IAND());
            IFNE ifne = new IFNE(null);
            il.append(ifne);
            il.append(new ICONST(0));
            il.append(new IRETURN());
            InstructionHandle handle = il.append(new ICONST(1));
            ifne.setTarget(handle);
            il.append(new IRETURN());

        } else {
            il.append(new ILOAD(1));
            for (int i = 0; i < num; i++) {
                il.append(new PUSH(constantPoolGen, ((32 * i) + 32)));
                IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
                il.append(if_icmpge);
                il.append(new ALOAD(0));
                il.append(instructionFactory.createGetField(classGen.getClassName(),
                        getLoadedFieldName(i),
                        Type.INT));
                il.append(new ICONST(1));
                il.append(new ILOAD(1));
                il.append(new ISHL());
                il.append(new IAND());
                IFEQ ifeq = new IFEQ(null);
                il.append(ifeq);
                il.append(new ICONST(1));
                GOTO aGoto = new GOTO(null);
                il.append(aGoto);
                InstructionHandle iconst0Handle = il.append(new ICONST(0));
                ifeq.setTarget(iconst0Handle);
                InstructionHandle gotoHandle = il.append(new IRETURN());
                aGoto.setTarget(gotoHandle);
                InstructionHandle iload1Handle = il.append(new ILOAD(1));
                if_icmpge.setTarget(iload1Handle);
            }
            // take last one and replace with ICONST_0
            InstructionHandle lastHandle = il.getEnd();
            InstructionHandle replaceHandle = il.append(new ICONST(0));
            try {
                il.delete(lastHandle);
            } catch (TargetLostException e) {
                InstructionHandle[] targets = e.getTargets();
                for (int i = 0; i < targets.length; i++) {
                    InstructionTargeter[] targeters = targets[i].getTargeters();
                    for (int j = 0; j < targeters.length; j++) {
                        targeters[j].updateTarget(targets[i], replaceHandle);
                    }
                }
            }
            il.append(new IRETURN());
        }

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addSetLoadedInt(String methodName) {

        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.VOID,
                new Type[]{Type.INT},
                new String[]{"fieldNo"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        int num = getNumOfControlFields();
        if (num == 1) {
            il.append(new ALOAD(0));
            il.append(new DUP());
            il.append(instructionFactory.createGetField(classGen.getClassName(),
                    getLoadedFieldName(0),
                    Type.INT));

            il.append(new ICONST(1));
            il.append(new ILOAD(1));
            il.append(new ISHL());
            il.append(new IOR());
            il.append(instructionFactory.createPutField(classGen.getClassName(),
                    getLoadedFieldName(0),
                    Type.INT));
            il.append(new RETURN());
        } else {
            il.append(new ILOAD(1));
            for (int i = 0; i < num; i++) {
                il.append(new PUSH(constantPoolGen, ((32 * i) + 32)));
                IF_ICMPGE if_icmpge = new IF_ICMPGE(null);
                il.append(if_icmpge);

                il.append(new ALOAD(0));
                il.append(new DUP());
                il.append(instructionFactory.createGetField(classGen.getClassName(),
                        getLoadedFieldName(i),
                        Type.INT));
                il.append(new ICONST(1));
                il.append(new ILOAD(1));
                il.append(new ISHL());
                il.append(new IOR());
                il.append(instructionFactory.createPutField(classGen.getClassName(),
                        getLoadedFieldName(i),
                        Type.INT));
                if (i != (num - 1)) {
                    il.append(new RETURN());
                    InstructionHandle iloadHandle = il.append(new ILOAD(1));
                    if_icmpge.setTarget(iloadHandle);
                } else {
                    InstructionHandle returnHandle = il.append(new RETURN());   // last return
                    if_icmpge.setTarget(returnHandle);
                }
            }

        }
        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }



    private final int getNumOfControlFields() {
        return (totlalManagedFields / 32) + 1;
    }

    private final String getDirtyFieldName(int index) {
        return DIRTY_FIELD_NAME + index;
    }

    private final String getLoadedFieldName(int index) {
        return LOADED_FIELD_NAME + index;
    }

    private void addFields() {
        int num = getNumOfControlFields();
        for (int i = 0; i < num; i++) {
            FieldGen fieldGenFilled = new FieldGen(// Added our int LOADED_FIELD_NAME , to see what has been loaded in
                    Constants.ACC_PRIVATE ,
                    Type.INT,
                    LOADED_FIELD_NAME + i,
                    constantPoolGen);
            makeSynthetic(fieldGenFilled);
            classGen.addField(fieldGenFilled.getField());

            FieldGen fieldGenDirtyFields = new FieldGen(// Added our int DIRTY_FIELD_NAME , to see what is dirty
                    Constants.ACC_PRIVATE ,
                    Type.INT,
                    DIRTY_FIELD_NAME + i,
                    constantPoolGen);
            makeSynthetic(fieldGenDirtyFields);
            classGen.addField(fieldGenDirtyFields.getField());

        }

        FieldGen fieldGenVersionField = new FieldGen(// Added our Version field
                Constants.ACC_PRIVATE ,
                Type.OBJECT,
                VERSION_FIELD_NAME,
                constantPoolGen);
        makeSynthetic(fieldGenVersionField);
        classGen.addField(fieldGenVersionField.getField());

        FieldGen fieldGenOIDField = new FieldGen(// Added our OID field
                Constants.ACC_PRIVATE ,
                Type.OBJECT,
                OID_FIELD_NAME ,
                constantPoolGen);
        makeSynthetic(fieldGenOIDField);
        classGen.addField(fieldGenOIDField.getField());
    }

    private void addGetOid(String methodName){
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,// | NEW Constants.ACC_FINAL,
                Type.OBJECT,
                new Type[]{},
                new String[]{},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(0));
        il.append(instructionFactory.createGetField(
                classGen.getClassName(),
                OID_FIELD_NAME,
                Type.OBJECT));
        il.append(new ARETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }

    private void addSetOid(String methodName) {
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.VOID,
                new Type[]{Type.OBJECT},
                new String[]{"oid"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(0));
        il.append(new ALOAD(1));
        il.append(instructionFactory.createPutField(
                classGen.getClassName(),
                OID_FIELD_NAME,
                Type.OBJECT));
        il.append(new RETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addGetVersion(String methodName) {
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.OBJECT,
                new Type[]{},
                new String[]{},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(0));
        il.append(instructionFactory.createGetField(
                classGen.getClassName(),
                VERSION_FIELD_NAME,
                Type.OBJECT));
        il.append(new ARETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }

    private void addGetStateManager(String methodName) {
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                new ObjectType(DETACHED_STATE_MANAGER),
                new Type[]{},
                new String[]{},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(0));
        il.append(instructionFactory.createGetField(classGen.getClassName(),
                "jdoStateManager",
                new ObjectType(STATE_MANAGER)));
        il.append(new INSTANCEOF(constantPoolGen.addClass(DETACHED_STATE_MANAGER)));
        IFEQ ifeq = new IFEQ(null);
        il.append(ifeq);
        il.append(new ALOAD(0));
        il.append(instructionFactory.createGetField(classGen.getClassName(),
                "jdoStateManager",
                new ObjectType(STATE_MANAGER)));
        il.append(instructionFactory.createCheckCast(new ObjectType(DETACHED_STATE_MANAGER)));
        il.append(new ARETURN());
        InstructionHandle nullHandle = il.append(new ACONST_NULL());
        ifeq.setTarget(nullHandle);
        il.append(new ARETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();

    }

    private void addSetVersion(String methodName) {
        InstructionList il = new InstructionList();
        MethodGen methodGen = new MethodGen(Constants.ACC_PUBLIC ,//| NEW Constants.ACC_FINAL,
                Type.VOID,
                new Type[]{Type.OBJECT},
                new String[]{"version"},
                methodName,
                classGen.getClassName(),
                il,
                constantPoolGen);

        il.append(new ALOAD(0));
        il.append(new ALOAD(1));
        il.append(instructionFactory.createPutField(
                classGen.getClassName(),
                VERSION_FIELD_NAME,
                Type.OBJECT));
        il.append(new RETURN());

        methodGen.setMaxLocals();
        methodGen.setMaxStack();
        classGen.addMethod(methodGen.getMethod());
        il.dispose();
    }

    private void addDetachInterfase() {
        classGen.addInterface(DETACHABLE_INTERFASE);
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.