openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r640685 [3/14] - in /openjpa/trunk: ./ openjpa-all/ openjpa-jdbc-5/ openjpa-jdbc/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/java/org/apache/open...
Date Tue, 25 Mar 2008 03:38:02 GMT
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java?rev=640685&r1=640684&r2=640685&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java Mon Mar 24 20:37:56 2008
@@ -1,1077 +1,1077 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.    
- */
-package org.apache.openjpa.enhance;
-
-import java.util.BitSet;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.kernel.AbstractPCData;
-import org.apache.openjpa.kernel.FetchConfiguration;
-import org.apache.openjpa.kernel.OpenJPAStateManager;
-import org.apache.openjpa.kernel.PCData;
-import org.apache.openjpa.kernel.StoreContext;
-import org.apache.openjpa.lib.log.Log;
-import org.apache.openjpa.lib.util.Localizer;
-import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap;
-import org.apache.openjpa.meta.ClassMetaData;
-import org.apache.openjpa.meta.FieldMetaData;
-import org.apache.openjpa.meta.JavaTypes;
-import org.apache.openjpa.util.InternalException;
-import serp.bytecode.BCClass;
-import serp.bytecode.BCField;
-import serp.bytecode.BCMethod;
-import serp.bytecode.Code;
-import serp.bytecode.Constants;
-import serp.bytecode.ExceptionHandler;
-import serp.bytecode.Instruction;
-import serp.bytecode.JumpInstruction;
-import serp.bytecode.LookupSwitchInstruction;
-
-/**
- * Generates {@link PCData} instances which avoid primitve wrappers
- * to optimize memory use and performance at the cost of slightly higher
- * startup time.
- *
- * @author Steve Kim
- * @nojavadoc
- * @since 0.3.2
- */
-public class PCDataGenerator
-    extends DynamicStorageGenerator {
-
-    private static final Localizer _loc = Localizer.forPackage
-        (PCDataGenerator.class);
-
-    protected static final String POSTFIX = "$openjpapcdata";
-
-    private final Map _generated = new ConcurrentHashMap();
-    private final OpenJPAConfiguration _conf;
-    private final Log _log;
-
-    public PCDataGenerator(OpenJPAConfiguration conf) {
-        _conf = conf;
-        _log = _conf.getLogFactory().getLog(OpenJPAConfiguration.LOG_ENHANCE);
-    }
-
-    /**
-     * Return the configuration.
-     */
-    public OpenJPAConfiguration getConfiguration() {
-        return _conf;
-    }
-
-    /**
-     * Return a {@link PCData} instance for the given oid and metadata.
-     */
-    public PCData generatePCData(Object oid, ClassMetaData meta) {
-        if (meta == null)
-            return null;
-        Class type = meta.getDescribedType();
-        DynamicStorage storage = (DynamicStorage) _generated.get(type);
-        if (storage == null) {
-            storage = generateStorage(meta);
-            _generated.put(type, storage);
-            if (_log.isTraceEnabled())
-                _log.trace(_loc.get("pcdata-created", type.getName(), meta));
-        }
-        DynamicPCData data = (DynamicPCData) storage.newInstance();
-        data.setId(oid);
-        data.setStorageGenerator(this);
-        finish(data, meta);
-        return data;
-    }
-
-    /**
-     * Actually generate the factory instance.
-     */
-    private DynamicStorage generateStorage(ClassMetaData meta) {
-        if (_log.isTraceEnabled())
-            _log.trace(_loc.get("pcdata-generate", meta));
-
-        FieldMetaData[] fields = meta.getFields();
-        int[] types = new int[fields.length];
-        for (int i = 0; i < types.length; i++)
-            types[i] = replaceType(fields[i]);
-        return generateStorage(types, meta);
-    }
-
-    /**
-     * Perform any final actions before the pcdata is returned to client code.
-     */
-    protected void finish(DynamicPCData data, ClassMetaData meta) {
-    }
-
-    protected int getCreateFieldMethods(int typeCode) {
-        if (typeCode >= JavaTypes.OBJECT)
-            return POLICY_SILENT;
-        // don't bother creating set/get<Primitive> methods
-        return POLICY_EMPTY;
-    }
-
-    protected void declareClasses(BCClass bc) {
-        super.declareClasses(bc);
-        bc.declareInterface(DynamicPCData.class);
-        bc.setSuperclass(AbstractPCData.class);
-    }
-
-    protected final String getClassName(Object obj) {
-        return getUniqueName(((ClassMetaData) obj).getDescribedType());
-    }
-
-    /**
-     * Creates a unique name for the given type's pcdata implementation.
-     */
-    protected String getUniqueName(Class type) {
-        return type.getName() + "$" + System.identityHashCode(type) + POSTFIX;
-    }
-
-    protected final void decorate(Object obj, BCClass bc, int[] types) {
-        super.decorate(obj, bc, types);
-        ClassMetaData meta = (ClassMetaData) obj;
-
-        enhanceConstructor(bc);
-        addBaseFields(bc);
-        addImplDataMethods(bc, meta);
-        addFieldImplDataMethods(bc, meta);
-        addVersionMethods(bc);
-        addGetType(bc, meta);
-        addLoadMethod(bc, meta);
-        addLoadWithFieldsMethod(bc, meta);
-        addStoreMethods(bc, meta);
-        addNewEmbedded(bc);
-        addGetData(bc);
-        decorate(bc, meta);
-    }
-
-    /**
-     * Apply additional decoration to generated class.
-     */
-    protected void decorate(BCClass bc, ClassMetaData meta) {
-    }
-
-    /**
-     * Enhance constructor to initialize fields
-     */
-    private void enhanceConstructor(BCClass bc) {
-        BCMethod cons = bc.getDeclaredMethod("<init>", (String[]) null);
-        Code code = cons.getCode(false);
-        code.afterLast();
-        code.previous();
-
-        // private BitSet loaded = new BitSet();
-        BCField loaded = addBeanField(bc, "loaded", BitSet.class);
-        loaded.setFinal(true);
-        code.aload().setThis();
-        code.anew().setType(BitSet.class);
-        code.dup();
-        code.constant().setValue(bc.getFields().length);
-        code.invokespecial().setMethod(BitSet.class, "<init>", void.class,
-            new Class[]{ int.class });
-        code.putfield().setField(loaded);
-
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    /**
-     * Have to load the type since it may not be available to the
-     * same classloader (i.e. rar vs. ear). The context classloader
-     * (i.e. the user app classloader) should be fine.
-     */
-    private void addGetType(BCClass bc, ClassMetaData meta) {
-        BCField type = bc.declareField("type", Class.class);
-        type.setStatic(true);
-        type.makePrivate();
-        // public Class getType() {
-        BCMethod getter = bc.declareMethod("getType", Class.class, null);
-        getter.makePublic();
-        Code code = getter.getCode(true);
-        // if (type == null) {
-        // 		try {
-        // 			type = Class.forName
-        // 				(meta.getDescribedType().getName(), true,
-        // 				Thread.currentThread().getContextClassLoader());
-        // 		} catch (ClassNotFoundException cnfe) {
-        // 			throw new InternalException();
-        // 		}
-        // }
-        code.getstatic().setField(type);
-
-        Collection jumps = new LinkedList();
-        jumps.add(code.ifnonnull());
-        ExceptionHandler handler = code.addExceptionHandler();
-
-        handler.setTryStart(code.constant().setValue
-            (meta.getDescribedType().getName()));
-        code.constant().setValue(true);
-        code.invokestatic().setMethod(Thread.class, "currentThread",
-            Thread.class, null);
-        code.invokevirtual().setMethod(Thread.class, "getContextClassLoader",
-            ClassLoader.class, null);
-        code.invokestatic().setMethod(Class.class, "forName", Class.class,
-            new Class[]{ String.class, boolean.class, ClassLoader.class });
-        code.putstatic().setField(type);
-        Instruction go2 = code.go2();
-        jumps.add(go2);
-        handler.setTryEnd(go2);
-        handler.setCatch(ClassNotFoundException.class);
-        handler.setHandlerStart(throwException
-            (code, InternalException.class));
-        setTarget(code.getstatic().setField(type), jumps);
-        code.areturn();
-
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    /**
-     * Declare standard dynamic pcdata fields.
-     */
-    private void addBaseFields(BCClass bc) {
-        addBeanField(bc, "id", Object.class);
-        BCField field = addBeanField(bc, "storageGenerator",
-            PCDataGenerator.class);
-        field.setAccessFlags(field.getAccessFlags()
-            | Constants.ACCESS_TRANSIENT);
-    }
-
-    /**
-     * Add methods for loading and storing class-level impl data.
-     */
-    private void addImplDataMethods(BCClass bc, ClassMetaData meta) {
-        // void storeImplData(OpenJPAStateManager);
-        BCMethod meth = bc.declareMethod("storeImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-        Code code = meth.getCode(true);
-
-        BCField impl = null;
-        if (!usesImplData(meta))
-            code.vreturn();
-        else {
-            // if (sm.isImplDataCacheable())
-            // 		setImplData(sm.getImplData());
-            impl = addBeanField(bc, "implData", Object.class);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "isImplDataCacheable", boolean.class, null);
-            JumpInstruction ifins = code.ifeq();
-            code.aload().setThis();
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getImplData", Object.class, null);
-            code.invokevirtual().setMethod("setImplData", void.class,
-                new Class[]{ Object.class });
-            ifins.setTarget(code.vreturn());
-        }
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-
-        // void loadImplData(OpenJPAStateManager);
-        meth = bc.declareMethod("loadImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-        code = meth.getCode(true);
-        if (!usesImplData(meta))
-            code.vreturn();
-        else {
-            // if (sm.getImplData() == null && implData != null)
-            // 		sm.setImplData(impl, true);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getImplData", Object.class, null);
-            JumpInstruction ifins = code.ifnonnull();
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            JumpInstruction ifins2 = code.ifnull();
-            code.aload().setParam(0);
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            code.constant().setValue(true);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "setImplData", void.class,
-                new Class[]{ Object.class, boolean.class });
-            Instruction ins = code.vreturn();
-            ifins.setTarget(ins);
-            ifins2.setTarget(ins);
-        }
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    /**
-     * Add methods for loading and storing class-level impl data.
-     */
-    private void addFieldImplDataMethods(BCClass bc, ClassMetaData meta) {
-        // public void loadImplData(OpenJPAStateManager sm, int i)
-        BCMethod meth = bc.declareMethod("loadImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class, int.class });
-        meth.makePrivate();
-        Code code = meth.getCode(true);
-
-        int count = countImplDataFields(meta);
-        BCField impl = null;
-        if (count == 0)
-            code.vreturn();
-        else {
-            // Object[] fieldImpl
-            impl = bc.declareField("fieldImpl", Object[].class);
-            impl.makePrivate();
-
-            // if (fieldImpl != null)
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            JumpInstruction ifins = code.ifnonnull();
-            code.vreturn();
-
-            // Object obj = null;
-            int obj = code.getNextLocalsIndex();
-            ifins.setTarget(code.constant().setNull());
-            code.astore().setLocal(obj);
-
-            // establish switch target, then move before it
-            Instruction target = code.aload().setLocal(obj);
-            code.previous();
-
-            // switch(i)
-            code.iload().setParam(1);
-            LookupSwitchInstruction lswitch = code.lookupswitch();
-            FieldMetaData[] fields = meta.getFields();
-            int cacheable = 0;
-            for (int i = 0; i < fields.length; i++) {
-                if (!usesImplData(fields[i]))
-                    continue;
-                // case x: obj = fieldImpl[y]; break;
-                lswitch.addCase(i, code.aload().setThis());
-                code.getfield().setField(impl);
-                code.constant().setValue(cacheable++);
-                code.aaload();
-                code.astore().setLocal(obj);
-                code.go2().setTarget(target);
-            }
-            lswitch.setDefaultTarget(target);
-
-            // if (obj != null)
-            code.next();    // jump back over target
-            ifins = code.ifnonnull();
-            code.vreturn();
-
-            // sm.setImplData(index, impl);
-            ifins.setTarget(code.aload().setParam(0));
-            code.iload().setParam(1);
-            code.aload().setLocal(obj);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "setImplData", void.class,
-                new Class[]{ int.class, Object.class });
-            code.vreturn();
-        }
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-
-        // void storeImplData(OpenJPAStateManager sm, int index, boolean loaded)
-        meth = bc.declareMethod("storeImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class, int.class, boolean.class });
-        code = meth.getCode(true);
-        if (count == 0)
-            code.vreturn();
-        else {
-            // int arrIdx = -1;
-            // switch(index)
-            int arrIdx = code.getNextLocalsIndex();
-            code.constant().setValue(-1);
-            code.istore().setLocal(arrIdx);
-            code.iload().setParam(1);
-            LookupSwitchInstruction lswitch = code.lookupswitch();
-
-            // establish switch target, then move before it
-            Instruction switchTarget = code.iload().setLocal(arrIdx);
-            code.previous();
-
-            FieldMetaData[] fields = meta.getFields();
-            int cacheable = 0;
-            for (int i = 0; i < fields.length; i++) {
-                if (!usesImplData(fields[i]))
-                    continue;
-                // case x: arrIdx = y; break;
-                lswitch.addCase(i, code.constant().setValue(cacheable++));
-                code.istore().setLocal(arrIdx);
-                code.go2().setTarget(switchTarget);
-            }
-            lswitch.setDefaultTarget(switchTarget);
-            code.next();    // step over switch target
-
-            // if (arrIdx != -1)
-            code.constant().setValue(-1);
-            JumpInstruction ifins = code.ificmpne();
-            code.vreturn();
-
-            // create null target, then move before it
-            Instruction nullTarget = code.aload().setThis();
-            code.previous();
-
-            // if (loaded)
-            ifins.setTarget(code.iload().setParam(2));
-            code.ifeq().setTarget(nullTarget);
-
-            // Object obj = sm.getImplData(index)
-            int obj = code.getNextLocalsIndex();
-            code.aload().setParam(0);
-            code.iload().setParam(1);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getImplData", Object.class, new Class[]{ int.class });
-            code.astore().setLocal(obj);
-
-            // if (obj != null)
-            code.aload().setLocal(obj);
-            code.ifnull().setTarget(nullTarget);
-
-            // if (fieldImpl == null)
-            // 		fieldImpl = new Object[fields];
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            ifins = code.ifnonnull();
-            code.aload().setThis();
-            code.constant().setValue(count);
-            code.anewarray().setType(Object.class);
-            code.putfield().setField(impl);
-
-            // fieldImpl[arrIdx] = obj;
-            // return;
-            ifins.setTarget(code.aload().setThis());
-            code.getfield().setField(impl);
-            code.iload().setLocal(arrIdx);
-            code.aload().setLocal(obj);
-            code.aastore();
-            code.vreturn();
-
-            // if (fieldImpl != null)
-            // 		fieldImpl[index] = null;
-            code.next(); // step over nullTarget
-            code.getfield().setField(impl);
-            ifins = code.ifnonnull();
-            code.vreturn();
-            ifins.setTarget(code.aload().setThis());
-            code.getfield().setField(impl);
-            code.iload().setLocal(arrIdx);
-            code.constant().setNull();
-            code.aastore();
-            code.vreturn();
-        }
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    /**
-     * Add methods for loading and storing version data.
-     */
-    protected void addVersionMethods(BCClass bc) {
-        // void storeVersion(OpenJPAStateManager sm);
-        addBeanField(bc, "version", Object.class);
-        BCMethod meth = bc.declareMethod("storeVersion", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-        Code code = meth.getCode(true);
-
-        // version = sm.getVersion();
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.invokeinterface()
-            .setMethod(OpenJPAStateManager.class, "getVersion",
-                Object.class, null);
-        code.putfield().setField("version", Object.class);
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-
-        // void loadVersion(OpenJPAStateManager sm)
-        meth = bc.declareMethod("loadVersion", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-        code = meth.getCode(true);
-
-        // if (sm.getVersion() == null)
-        // 		sm.setVersion(version);
-        code.aload().setParam(0);
-        code.invokeinterface().setMethod(OpenJPAStateManager.class,
-            "getVersion", Object.class, null);
-        JumpInstruction ifins = code.ifnonnull();
-        code.aload().setParam(0);
-        code.aload().setThis();
-        code.getfield().setField("version", Object.class);
-        code.invokeinterface()
-            .setMethod(OpenJPAStateManager.class, "setVersion",
-                void.class, new Class[]{ Object.class });
-        ifins.setTarget(code.vreturn());
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    private void addLoadMethod(BCClass bc, ClassMetaData meta) {
-        // public void load(OpenJPAStateManager sm, FetchConfiguration fetch,
-        // 		Object context)
-        Code code = addLoadMethod(bc, false);
-        FieldMetaData[] fmds = meta.getFields();
-        Collection jumps = new LinkedList();
-        Collection jumps2;
-		
-        int local = code.getNextLocalsIndex();
-        code.constant().setNull();
-        code.astore().setLocal(local);
-        int inter = code.getNextLocalsIndex();
-        code.constant().setNull();
-        code.astore().setLocal(inter);
-
-        int objectCount = 0;
-        boolean intermediate;
-        for (int i = 0; i < fmds.length; i++) {
-            jumps2 = new LinkedList();
-            intermediate = usesIntermediate(fmds[i]);
-            setTarget(code.aload().setThis(), jumps);
-            // if (loaded.get(i)) or (!loaded.get(i)) depending on inter resp
-            code.getfield().setField("loaded", BitSet.class);
-            code.constant().setValue(i);
-            code.invokevirtual().setMethod(BitSet.class, "get",
-                boolean.class, new Class[]{ int.class });
-            jumps.add(code.ifne());
-
-            if (intermediate)
-                addLoadIntermediate(code, i, objectCount, jumps2, inter);
-            jumps2.add(code.go2());
-
-            // if (fetch.requiresFetch(fmds[i])!=FetchConfiguration.FETCH_NONE)
-            setTarget(code.aload().setParam(1), jumps);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getMetaData", ClassMetaData.class, null);
-            code.constant().setValue(fmds[i].getIndex());
-            code.invokevirtual().setMethod(ClassMetaData.class,
-                "getField", FieldMetaData.class, new Class[]{int.class});
-            code.invokeinterface().setMethod (FetchConfiguration.class, 
-                "requiresFetch", int.class, new Class[]{FieldMetaData.class});
-            code.constant().setValue(FetchConfiguration.FETCH_NONE);
-            jumps2.add(code.ificmpeq());
-            addLoad(bc, code, fmds[i], objectCount, local, false);
-
-            jumps = jumps2;
-            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
-                objectCount++;
-        }
-        setTarget(code.vreturn(), jumps);
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    private void addLoadWithFieldsMethod(BCClass bc, ClassMetaData meta) {
-        Code code = addLoadMethod(bc, true);
-        // public void load(OpenJPAStateManager sm, BitSet fields,
-        // 		FetchConfiguration fetch, Object conn)
-        FieldMetaData[] fmds = meta.getFields();
-        Collection jumps = new LinkedList();
-        Collection jumps2;
-        int objectCount = 0;
-        boolean intermediate;
-        int local = code.getNextLocalsIndex();
-        code.constant().setNull();
-        code.astore().setLocal(local);
-        int inter = code.getNextLocalsIndex();
-        code.constant().setNull();
-        code.astore().setLocal(inter);
-
-        for (int i = 0; i < fmds.length; i++) {
-            jumps2 = new LinkedList();
-            intermediate = usesIntermediate(fmds[i]);
-            // if (fields.get(i))
-            // {
-            // 		if (loaded.get(i))
-            setTarget(code.aload().setParam(1), jumps);
-            code.constant().setValue(i);
-            code.invokevirtual().setMethod(BitSet.class, "get",
-                boolean.class, new Class[]{ int.class });
-            jumps2.add(code.ifeq());
-            code.aload().setThis();
-            code.getfield().setField("loaded", BitSet.class);
-            code.constant().setValue(i);
-            code.invokevirtual().setMethod(BitSet.class, "get",
-                boolean.class, new Class[]{ int.class });
-            if (intermediate)
-                jumps.add(code.ifeq());
-            else
-                jumps2.add(code.ifeq());
-
-            addLoad(bc, code, fmds[i], objectCount, local, true);
-            if (usesImplData(fmds[i])) {
-                // loadImplData(sm, i);
-                code.aload().setThis();
-                code.aload().setParam(0);
-                code.constant().setValue(i);
-                code.invokevirtual().setMethod("loadImplData", void.class,
-                    new Class[]{ OpenJPAStateManager.class, int.class });
-            }
-
-            // fields.clear(i);
-            code.aload().setParam(1);
-            code.constant().setValue(i);
-            code.invokevirtual().setMethod(BitSet.class, "clear", void.class,
-                new Class[] { int.class });
-
-            jumps2.add(code.go2());
-
-            if (intermediate)
-                setTarget(addLoadIntermediate
-                    (code, i, objectCount, jumps2, inter), jumps);
-
-            jumps = jumps2;
-            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
-                objectCount++;
-        }
-        setTarget(code.vreturn(), jumps);
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
-    }
-
-    /**
-     * Declare and start the base load method.
-     */
-    private Code addLoadMethod(BCClass bc, boolean fields) {
-        Class[] args = null;
-        if (fields)
-            args = new Class[]{ OpenJPAStateManager.class, BitSet.class,
-                FetchConfiguration.class, Object.class };
-        else
-            args = new Class[]{ OpenJPAStateManager.class,
-                FetchConfiguration.class, Object.class };
-        BCMethod load = bc.declareMethod("load", void.class, args);
-        Code code = load.getCode(true);
-
-        //loadVersion(sm);
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("loadVersion", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-
-        //loadImplData(sm);
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("loadImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-        return code;
-    }
-
-    /**
-     * Add the field load.
-     */
-    private Instruction addLoad(BCClass bc, Code code, FieldMetaData fmd,
-        int objectCount, int local, boolean fields) {
-        int index = fmd.getIndex();
-        int typeCode = replaceType(fmd);
-        Instruction first;
-        if (typeCode < JavaTypes.OBJECT) {
-            // sm.store<type>(i, field<i>)
-            Class type = forType(fmd.getTypeCode());
-            first = code.aload().setParam(0);
-            code.constant().setValue(index);
-            code.aload().setThis();
-            code.getfield().setField(getFieldName(index), type);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "store" + StringUtils.capitalize(type.getName()),
-                void.class, new Class[]{ int.class, type });
-        } else {
-            // fmd = sm.getMetaData().getField(i);
-            int offset = fields ? 1 : 0;
-            first = code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getMetaData", ClassMetaData.class, null);
-            code.constant().setValue(fmd.getIndex());
-            code.invokevirtual().setMethod(ClassMetaData.class, "getField",
-                FieldMetaData.class, new Class[]{ int.class });
-            code.astore().setLocal(local);
-            // sm.storeField(i, toField(sm, fmd, objects[objectCount],
-            // 		fetch, context);
-            code.aload().setParam(0);
-            code.constant().setValue(index);
-            code.aload().setThis();
-            code.aload().setParam(0);
-            code.aload().setLocal(local);
-            code.aload().setThis();
-            code.getfield().setField("objects", Object[].class);
-            code.constant().setValue(objectCount);
-            code.aaload();
-            code.aload().setParam(1 + offset);
-            code.aload().setParam(2 + offset);
-            code.invokevirtual().setMethod(bc.getName(), "toField",
-                Object.class.getName(), toStrings(new Class[]{ 
-                OpenJPAStateManager.class, FieldMetaData.class,
-                Object.class, FetchConfiguration.class, Object.class }));
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "storeField", void.class,
-                new Class[]{ int.class, Object.class });
-        }
-        return first;
-    }
-
-    /**
-     * Load intermediate data if possible.
-     */
-    private Instruction addLoadIntermediate(Code code, int index,
-        int objectCount, Collection jumps2, int inter) {
-        // {
-        // 		Object inter = objects[objectCount];
-        Instruction first = code.aload().setThis();
-        code.getfield().setField("objects", Object[].class);
-        code.constant().setValue(objectCount);
-        code.aaload();
-        code.astore().setLocal(inter);
-        // 		if (inter != null && !sm.getLoaded().get(index))
-        code.aload().setLocal(inter);
-        jumps2.add(code.ifnull());
-        code.aload().setParam(0);
-        code.invokeinterface().setMethod(OpenJPAStateManager.class,
-            "getLoaded", BitSet.class, null);
-        code.constant().setValue(index);
-        code.invokevirtual().setMethod(BitSet.class, "get",
-            boolean.class, new Class[]{ int.class });
-        jumps2.add(code.ifne());
-        //			sm.setIntermediate(index, inter);
-        //	}  // end else
-        code.aload().setParam(0);
-        code.constant().setValue(index);
-        code.aload().setLocal(inter);
-        code.invokeinterface().setMethod(OpenJPAStateManager.class,
-            "setIntermediate", void.class,
-            new Class[]{ int.class, Object.class });
-        return first;
-    }
-
-    private void addStoreMethods(BCClass bc, ClassMetaData meta) {
-        // i.e. void store(OpenJPAStateManager sm, BitSet fields);
-        addStoreMethod(bc, meta, true);
-        // i.e. void store(OpenJPAStateManager sm);
-        addStoreMethod(bc, meta, false);
-    }
-
-    private void addStoreMethod(BCClass bc, ClassMetaData meta,
-        boolean fields) {
-        BCMethod store;
-        if (fields)
-            store = bc.declareMethod("store", void.class,
-                new Class[]{ OpenJPAStateManager.class, BitSet.class });
-        else
-            store = bc.declareMethod("store", void.class,
-                new Class[]{ OpenJPAStateManager.class });
-        Code code = store.getCode(true);
-
-        // initialize();
-        code.aload().setThis();
-        code.invokevirtual().setMethod("initialize", void.class, null);
-
-        // storeVersion(sm);
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("storeVersion", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-
-        // storeImplData(sm);
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("storeImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class });
-
-        FieldMetaData[] fmds = meta.getFields();
-        Collection jumps = new LinkedList();
-        int objectCount = 0;
-        for (int i = 0; i < fmds.length; i++) {
-            if (fields) {
-                //  if (fields != null && fields.get(index))
-                setTarget(code.aload().setParam(1), jumps);
-                jumps.add(code.ifnull());
-                code.aload().setParam(1);
-                code.constant().setValue(i);
-                code.invokevirtual().setMethod(BitSet.class, "get",
-                    boolean.class, new Class[]{ int.class });
-                jumps.add(code.ifeq());
-            } else {
-                // if (sm.getLoaded().get(index)))
-                setTarget(code.aload().setParam(0), jumps);
-                code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                    "getLoaded", BitSet.class, null);
-                code.constant().setValue(i);
-                code.invokevirtual().setMethod(BitSet.class, "get",
-                    boolean.class, new Class[]{ int.class });
-                jumps.add(code.ifeq());
-            }
-            addStore(bc, code, fmds[i], objectCount);
-            if (usesIntermediate(fmds[i])) {
-                JumpInstruction elseIns = code.go2();
-                // else if (!loaded.get(index))
-                setTarget(code.aload().setThis(), jumps);
-                jumps.add(elseIns);
-                code.getfield().setField("loaded", BitSet.class);
-                code.constant().setValue(i);
-                code.invokevirtual().setMethod(BitSet.class, "get",
-                    boolean.class, new Class[]{ int.class });
-                jumps.add(code.ifne());
-                // Object val = sm.getIntermediate(index);
-                // if (val != null)
-                // 		objects[objectCount] = val;
-                code.aload().setParam(0);
-                code.constant().setValue(i);
-                code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                    "getIntermediate", Object.class, new Class[]{ int.class });
-                int local = code.getNextLocalsIndex();
-                code.astore().setLocal(local);
-                code.aload().setLocal(local);
-                jumps.add(code.ifnull());
-                code.aload().setThis();
-                code.getfield().setField("objects", Object[].class);
-                code.constant().setValue(objectCount);
-                code.aload().setLocal(local);
-                code.aastore();
-            }
-            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
-                objectCount++;
-        }
-        setTarget(code.vreturn(), jumps);
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-    }
-
-    private void addStore(BCClass bc, Code code, FieldMetaData fmd,
-        int objectCount) {
-        int typeCode = replaceType(fmd);
-        int index = fmd.getIndex();
-        if (typeCode < JavaTypes.OBJECT) {
-            Class type = forType(typeCode);
-            // field<i> = sm.fetch<Type>(index)
-            code.aload().setThis();
-            code.aload().setParam(0);
-            code.constant().setValue(index);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "fetch" + StringUtils.capitalize(type.getName()), type,
-                new Class[]{ int.class });
-            code.putfield().setField(getFieldName(index), type);
-            code.aload().setThis();
-            code.getfield().setField("loaded", BitSet.class);
-            code.constant().setValue(index);
-            code.invokevirtual().setMethod(BitSet.class, "set", void.class,
-                new Class[]{ int.class });
-        } else {
-            // Object val = toData(sm.getMetaData().getField(index),
-            // 		sm.fetchField(index, false), sm.getContext());
-            int local = code.getNextLocalsIndex();
-            code.aload().setThis();
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getMetaData", ClassMetaData.class, null);
-            code.constant().setValue(fmd.getIndex());
-            code.invokevirtual().setMethod(ClassMetaData.class,
-                "getField", FieldMetaData.class, new Class[]{ int.class });
-            code.aload().setParam(0);
-            code.constant().setValue(fmd.getIndex());
-            code.constant().setValue(false);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "fetchField", Object.class, new Class[]
-                { int.class, boolean.class });
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getContext", StoreContext.class, null);
-            code.invokevirtual().setMethod(bc.getName(), "toData",
-                Object.class.getName(), toStrings(new Class []{
-                FieldMetaData.class, Object.class, StoreContext.class }));
-            code.astore().setLocal(local);
-
-            // if (val == NULL) {
-            // 		val = null;
-            // 		loaded.clear(index);
-            // 	} else
-            // 		loaded.set(index);
-            // 	objects[objectCount] = val;
-            code.aload().setLocal(local);
-            code.getstatic().setField(AbstractPCData.class, "NULL",
-                Object.class);
-            JumpInstruction ifins = code.ifacmpne();
-            code.constant().setNull();
-            code.astore().setLocal(local);
-            code.aload().setThis();
-            code.getfield().setField("loaded", BitSet.class);
-            code.constant().setValue(index);
-            code.invokevirtual().setMethod(BitSet.class, "clear", void.class,
-                new Class[]{ int.class });
-            JumpInstruction go2 = code.go2();
-            ifins.setTarget(code.aload().setThis());
-            code.getfield().setField("loaded", BitSet.class);
-            code.constant().setValue(index);
-            code.invokevirtual().setMethod(BitSet.class, "set", void.class,
-                new Class[]{ int.class });
-            go2.setTarget(code.aload().setThis());
-            code.getfield().setField("objects", Object[].class);
-            code.constant().setValue(objectCount);
-            code.aload().setLocal(local);
-            code.aastore();
-        }
-        if (!usesImplData(fmd))
-            return;
-
-        // storeImplData(sm, i, loaded.get(i);
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.constant().setValue(index);
-        code.aload().setThis();
-        code.getfield().setField("loaded", BitSet.class);
-        code.constant().setValue(index);
-        code.invokevirtual().setMethod(BitSet.class, "get", boolean.class,
-            new Class[]{ int.class });
-        code.invokevirtual().setMethod("storeImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class, int.class, boolean.class });
-    }
-
-    private void addNewEmbedded(BCClass bc) {
-        // void newEmbeddedPCData(OpenJPAStateManager embedded)
-        BCMethod meth = bc.declareMethod("newEmbeddedPCData", PCData.class,
-            new Class[]{ OpenJPAStateManager.class });
-        Code code = meth.getCode(true);
-        // return getStorageGenerator().generatePCData
-        // 		(sm.getId(), sm.getMetaData());
-        code.aload().setThis();
-        code.getfield().setField("storageGenerator", PCDataGenerator.class);
-        code.aload().setParam(0);
-        code.invokeinterface().setMethod(OpenJPAStateManager.class,
-            "getId", Object.class, null);
-        code.aload().setParam(0);
-        code.invokeinterface().setMethod(OpenJPAStateManager.class,
-            "getMetaData", ClassMetaData.class, null);
-        code.invokevirtual().setMethod(PCDataGenerator.class,
-            "generatePCData", PCData.class, new Class[]
-            { Object.class, ClassMetaData.class });
-        code.areturn();
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-    }
-
-    private void addGetData(BCClass bc) {
-        // return getObjectField(i);
-        BCMethod method = bc.declareMethod("getData", Object.class,
-            new Class[]{ int.class });
-        Code code = method.getCode(true);
-        code.aload().setThis();
-        code.iload().setParam(0);
-        code.invokevirtual().setMethod("getObject", Object.class,
-            new Class[]{ int.class });
-        code.areturn();
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-    }
-
-    /////////////
-    // Utilities
-    /////////////
-
-    /**
-     * Return a valid {@link JavaTypes} constant for the given field
-     */
-    protected int replaceType(FieldMetaData fmd) {
-        if (usesIntermediate(fmd))
-            return JavaTypes.OBJECT;
-        return fmd.getTypeCode();
-    }
-
-    /**
-     * Whether the given field uses a cacheable intermediate value.
-     */
-    protected boolean usesIntermediate(FieldMetaData fmd) {
-        return fmd.usesIntermediate();
-    }
-
-    /**
-     * Whether the given type might have cacheable class-level impl data.
-     */
-    protected boolean usesImplData(ClassMetaData meta) {
-        return true;
-    }
-
-    /**
-     * Whether the given field might have cacheable impl data.
-     */
-    protected boolean usesImplData(FieldMetaData fmd) {
-        return fmd.usesImplData() == null;
-    }
-
-    /**
-     * The number of fields with cacheable impl data.
-     */
-    private int countImplDataFields(ClassMetaData meta) {
-        FieldMetaData[] fmds = meta.getFields();
-        int count = 0;
-        for (int i = 0; i < fmds.length; i++)
-            if (usesImplData(fmds[i]))
-                count++;
-        return count;
-    }
-
-    /**
-     * Add method which defers to AbstractPCData.
-     */
-    protected void callAbstractPCData(BCClass bc, String name, Class retType,
-        Class[] args) {
-        BCMethod meth = bc.declareMethod(name, retType, args);
-        Code code = meth.getCode(true);
-        code.aload().setThis();
-        for (int i = 0; i < args.length; i++)
-            code.xload().setParam(i).setType(args[i]);
-        code.invokevirtual().setMethod(AbstractPCData.class, name, retType,
-            args);
-        if (!void.class.equals(retType))
-            code.xreturn().setType(retType);
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-    }
-
-    /**
-     * Set the collection of {@link JumpInstruction}s to the given instruction,
-     * clearing the collection in the process.
-     */
-    protected void setTarget(Instruction ins, Collection jumps) {
-        for (Iterator it = jumps.iterator(); it.hasNext();)
-            ((JumpInstruction) it.next()).setTarget(ins);
-        jumps.clear();
-    }
-
-    /**
-     * Transform the given array of classes to strings.
-     */
-    private static String[] toStrings(Class[] cls) {
-        String[] strings = new String[cls.length];
-        for (int i = 0; i < strings.length; i++)
-            strings[i] = cls[i].getName();
-        return strings;
-    }
-
-    /**
-     * Dynamic {@link PCData}s generated will implement this interface
-     * to simplify initialization.
-     */
-    public static interface DynamicPCData extends PCData {
-
-        public void setId(Object oid);
-
-        public PCDataGenerator getStorageGenerator();
-
-        public void setStorageGenerator (PCDataGenerator generator);
-	}
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.enhance;
+
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.kernel.AbstractPCData;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.PCData;
+import org.apache.openjpa.kernel.StoreContext;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.InternalException;
+import serp.bytecode.BCClass;
+import serp.bytecode.BCField;
+import serp.bytecode.BCMethod;
+import serp.bytecode.Code;
+import serp.bytecode.Constants;
+import serp.bytecode.ExceptionHandler;
+import serp.bytecode.Instruction;
+import serp.bytecode.JumpInstruction;
+import serp.bytecode.LookupSwitchInstruction;
+
+/**
+ * Generates {@link PCData} instances which avoid primitve wrappers
+ * to optimize memory use and performance at the cost of slightly higher
+ * startup time.
+ *
+ * @author Steve Kim
+ * @nojavadoc
+ * @since 0.3.2
+ */
+public class PCDataGenerator
+    extends DynamicStorageGenerator {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (PCDataGenerator.class);
+
+    protected static final String POSTFIX = "$openjpapcdata";
+
+    private final Map _generated = new ConcurrentHashMap();
+    private final OpenJPAConfiguration _conf;
+    private final Log _log;
+
+    public PCDataGenerator(OpenJPAConfiguration conf) {
+        _conf = conf;
+        _log = _conf.getLogFactory().getLog(OpenJPAConfiguration.LOG_ENHANCE);
+    }
+
+    /**
+     * Return the configuration.
+     */
+    public OpenJPAConfiguration getConfiguration() {
+        return _conf;
+    }
+
+    /**
+     * Return a {@link PCData} instance for the given oid and metadata.
+     */
+    public PCData generatePCData(Object oid, ClassMetaData meta) {
+        if (meta == null)
+            return null;
+        Class type = meta.getDescribedType();
+        DynamicStorage storage = (DynamicStorage) _generated.get(type);
+        if (storage == null) {
+            storage = generateStorage(meta);
+            _generated.put(type, storage);
+            if (_log.isTraceEnabled())
+                _log.trace(_loc.get("pcdata-created", type.getName(), meta));
+        }
+        DynamicPCData data = (DynamicPCData) storage.newInstance();
+        data.setId(oid);
+        data.setStorageGenerator(this);
+        finish(data, meta);
+        return data;
+    }
+
+    /**
+     * Actually generate the factory instance.
+     */
+    private DynamicStorage generateStorage(ClassMetaData meta) {
+        if (_log.isTraceEnabled())
+            _log.trace(_loc.get("pcdata-generate", meta));
+
+        FieldMetaData[] fields = meta.getFields();
+        int[] types = new int[fields.length];
+        for (int i = 0; i < types.length; i++)
+            types[i] = replaceType(fields[i]);
+        return generateStorage(types, meta);
+    }
+
+    /**
+     * Perform any final actions before the pcdata is returned to client code.
+     */
+    protected void finish(DynamicPCData data, ClassMetaData meta) {
+    }
+
+    protected int getCreateFieldMethods(int typeCode) {
+        if (typeCode >= JavaTypes.OBJECT)
+            return POLICY_SILENT;
+        // don't bother creating set/get<Primitive> methods
+        return POLICY_EMPTY;
+    }
+
+    protected void declareClasses(BCClass bc) {
+        super.declareClasses(bc);
+        bc.declareInterface(DynamicPCData.class);
+        bc.setSuperclass(AbstractPCData.class);
+    }
+
+    protected final String getClassName(Object obj) {
+        return getUniqueName(((ClassMetaData) obj).getDescribedType());
+    }
+
+    /**
+     * Creates a unique name for the given type's pcdata implementation.
+     */
+    protected String getUniqueName(Class type) {
+        return type.getName() + "$" + System.identityHashCode(type) + POSTFIX;
+    }
+
+    protected final void decorate(Object obj, BCClass bc, int[] types) {
+        super.decorate(obj, bc, types);
+        ClassMetaData meta = (ClassMetaData) obj;
+
+        enhanceConstructor(bc);
+        addBaseFields(bc);
+        addImplDataMethods(bc, meta);
+        addFieldImplDataMethods(bc, meta);
+        addVersionMethods(bc);
+        addGetType(bc, meta);
+        addLoadMethod(bc, meta);
+        addLoadWithFieldsMethod(bc, meta);
+        addStoreMethods(bc, meta);
+        addNewEmbedded(bc);
+        addGetData(bc);
+        decorate(bc, meta);
+    }
+
+    /**
+     * Apply additional decoration to generated class.
+     */
+    protected void decorate(BCClass bc, ClassMetaData meta) {
+    }
+
+    /**
+     * Enhance constructor to initialize fields
+     */
+    private void enhanceConstructor(BCClass bc) {
+        BCMethod cons = bc.getDeclaredMethod("<init>", (String[]) null);
+        Code code = cons.getCode(false);
+        code.afterLast();
+        code.previous();
+
+        // private BitSet loaded = new BitSet();
+        BCField loaded = addBeanField(bc, "loaded", BitSet.class);
+        loaded.setFinal(true);
+        code.aload().setThis();
+        code.anew().setType(BitSet.class);
+        code.dup();
+        code.constant().setValue(bc.getFields().length);
+        code.invokespecial().setMethod(BitSet.class, "<init>", void.class,
+            new Class[]{ int.class });
+        code.putfield().setField(loaded);
+
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    /**
+     * Have to load the type since it may not be available to the
+     * same classloader (i.e. rar vs. ear). The context classloader
+     * (i.e. the user app classloader) should be fine.
+     */
+    private void addGetType(BCClass bc, ClassMetaData meta) {
+        BCField type = bc.declareField("type", Class.class);
+        type.setStatic(true);
+        type.makePrivate();
+        // public Class getType() {
+        BCMethod getter = bc.declareMethod("getType", Class.class, null);
+        getter.makePublic();
+        Code code = getter.getCode(true);
+        // if (type == null) {
+        // 		try {
+        // 			type = Class.forName
+        // 				(meta.getDescribedType().getName(), true,
+        // 				Thread.currentThread().getContextClassLoader());
+        // 		} catch (ClassNotFoundException cnfe) {
+        // 			throw new InternalException();
+        // 		}
+        // }
+        code.getstatic().setField(type);
+
+        Collection jumps = new LinkedList();
+        jumps.add(code.ifnonnull());
+        ExceptionHandler handler = code.addExceptionHandler();
+
+        handler.setTryStart(code.constant().setValue
+            (meta.getDescribedType().getName()));
+        code.constant().setValue(true);
+        code.invokestatic().setMethod(Thread.class, "currentThread",
+            Thread.class, null);
+        code.invokevirtual().setMethod(Thread.class, "getContextClassLoader",
+            ClassLoader.class, null);
+        code.invokestatic().setMethod(Class.class, "forName", Class.class,
+            new Class[]{ String.class, boolean.class, ClassLoader.class });
+        code.putstatic().setField(type);
+        Instruction go2 = code.go2();
+        jumps.add(go2);
+        handler.setTryEnd(go2);
+        handler.setCatch(ClassNotFoundException.class);
+        handler.setHandlerStart(throwException
+            (code, InternalException.class));
+        setTarget(code.getstatic().setField(type), jumps);
+        code.areturn();
+
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    /**
+     * Declare standard dynamic pcdata fields.
+     */
+    private void addBaseFields(BCClass bc) {
+        addBeanField(bc, "id", Object.class);
+        BCField field = addBeanField(bc, "storageGenerator",
+            PCDataGenerator.class);
+        field.setAccessFlags(field.getAccessFlags()
+            | Constants.ACCESS_TRANSIENT);
+    }
+
+    /**
+     * Add methods for loading and storing class-level impl data.
+     */
+    private void addImplDataMethods(BCClass bc, ClassMetaData meta) {
+        // void storeImplData(OpenJPAStateManager);
+        BCMethod meth = bc.declareMethod("storeImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+        Code code = meth.getCode(true);
+
+        BCField impl = null;
+        if (!usesImplData(meta))
+            code.vreturn();
+        else {
+            // if (sm.isImplDataCacheable())
+            // 		setImplData(sm.getImplData());
+            impl = addBeanField(bc, "implData", Object.class);
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "isImplDataCacheable", boolean.class, null);
+            JumpInstruction ifins = code.ifeq();
+            code.aload().setThis();
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getImplData", Object.class, null);
+            code.invokevirtual().setMethod("setImplData", void.class,
+                new Class[]{ Object.class });
+            ifins.setTarget(code.vreturn());
+        }
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+
+        // void loadImplData(OpenJPAStateManager);
+        meth = bc.declareMethod("loadImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+        code = meth.getCode(true);
+        if (!usesImplData(meta))
+            code.vreturn();
+        else {
+            // if (sm.getImplData() == null && implData != null)
+            // 		sm.setImplData(impl, true);
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getImplData", Object.class, null);
+            JumpInstruction ifins = code.ifnonnull();
+            code.aload().setThis();
+            code.getfield().setField(impl);
+            JumpInstruction ifins2 = code.ifnull();
+            code.aload().setParam(0);
+            code.aload().setThis();
+            code.getfield().setField(impl);
+            code.constant().setValue(true);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "setImplData", void.class,
+                new Class[]{ Object.class, boolean.class });
+            Instruction ins = code.vreturn();
+            ifins.setTarget(ins);
+            ifins2.setTarget(ins);
+        }
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    /**
+     * Add methods for loading and storing class-level impl data.
+     */
+    private void addFieldImplDataMethods(BCClass bc, ClassMetaData meta) {
+        // public void loadImplData(OpenJPAStateManager sm, int i)
+        BCMethod meth = bc.declareMethod("loadImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class, int.class });
+        meth.makePrivate();
+        Code code = meth.getCode(true);
+
+        int count = countImplDataFields(meta);
+        BCField impl = null;
+        if (count == 0)
+            code.vreturn();
+        else {
+            // Object[] fieldImpl
+            impl = bc.declareField("fieldImpl", Object[].class);
+            impl.makePrivate();
+
+            // if (fieldImpl != null)
+            code.aload().setThis();
+            code.getfield().setField(impl);
+            JumpInstruction ifins = code.ifnonnull();
+            code.vreturn();
+
+            // Object obj = null;
+            int obj = code.getNextLocalsIndex();
+            ifins.setTarget(code.constant().setNull());
+            code.astore().setLocal(obj);
+
+            // establish switch target, then move before it
+            Instruction target = code.aload().setLocal(obj);
+            code.previous();
+
+            // switch(i)
+            code.iload().setParam(1);
+            LookupSwitchInstruction lswitch = code.lookupswitch();
+            FieldMetaData[] fields = meta.getFields();
+            int cacheable = 0;
+            for (int i = 0; i < fields.length; i++) {
+                if (!usesImplData(fields[i]))
+                    continue;
+                // case x: obj = fieldImpl[y]; break;
+                lswitch.addCase(i, code.aload().setThis());
+                code.getfield().setField(impl);
+                code.constant().setValue(cacheable++);
+                code.aaload();
+                code.astore().setLocal(obj);
+                code.go2().setTarget(target);
+            }
+            lswitch.setDefaultTarget(target);
+
+            // if (obj != null)
+            code.next();    // jump back over target
+            ifins = code.ifnonnull();
+            code.vreturn();
+
+            // sm.setImplData(index, impl);
+            ifins.setTarget(code.aload().setParam(0));
+            code.iload().setParam(1);
+            code.aload().setLocal(obj);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "setImplData", void.class,
+                new Class[]{ int.class, Object.class });
+            code.vreturn();
+        }
+        code.calculateMaxLocals();
+        code.calculateMaxStack();
+
+        // void storeImplData(OpenJPAStateManager sm, int index, boolean loaded)
+        meth = bc.declareMethod("storeImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class, int.class, boolean.class });
+        code = meth.getCode(true);
+        if (count == 0)
+            code.vreturn();
+        else {
+            // int arrIdx = -1;
+            // switch(index)
+            int arrIdx = code.getNextLocalsIndex();
+            code.constant().setValue(-1);
+            code.istore().setLocal(arrIdx);
+            code.iload().setParam(1);
+            LookupSwitchInstruction lswitch = code.lookupswitch();
+
+            // establish switch target, then move before it
+            Instruction switchTarget = code.iload().setLocal(arrIdx);
+            code.previous();
+
+            FieldMetaData[] fields = meta.getFields();
+            int cacheable = 0;
+            for (int i = 0; i < fields.length; i++) {
+                if (!usesImplData(fields[i]))
+                    continue;
+                // case x: arrIdx = y; break;
+                lswitch.addCase(i, code.constant().setValue(cacheable++));
+                code.istore().setLocal(arrIdx);
+                code.go2().setTarget(switchTarget);
+            }
+            lswitch.setDefaultTarget(switchTarget);
+            code.next();    // step over switch target
+
+            // if (arrIdx != -1)
+            code.constant().setValue(-1);
+            JumpInstruction ifins = code.ificmpne();
+            code.vreturn();
+
+            // create null target, then move before it
+            Instruction nullTarget = code.aload().setThis();
+            code.previous();
+
+            // if (loaded)
+            ifins.setTarget(code.iload().setParam(2));
+            code.ifeq().setTarget(nullTarget);
+
+            // Object obj = sm.getImplData(index)
+            int obj = code.getNextLocalsIndex();
+            code.aload().setParam(0);
+            code.iload().setParam(1);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getImplData", Object.class, new Class[]{ int.class });
+            code.astore().setLocal(obj);
+
+            // if (obj != null)
+            code.aload().setLocal(obj);
+            code.ifnull().setTarget(nullTarget);
+
+            // if (fieldImpl == null)
+            // 		fieldImpl = new Object[fields];
+            code.aload().setThis();
+            code.getfield().setField(impl);
+            ifins = code.ifnonnull();
+            code.aload().setThis();
+            code.constant().setValue(count);
+            code.anewarray().setType(Object.class);
+            code.putfield().setField(impl);
+
+            // fieldImpl[arrIdx] = obj;
+            // return;
+            ifins.setTarget(code.aload().setThis());
+            code.getfield().setField(impl);
+            code.iload().setLocal(arrIdx);
+            code.aload().setLocal(obj);
+            code.aastore();
+            code.vreturn();
+
+            // if (fieldImpl != null)
+            // 		fieldImpl[index] = null;
+            code.next(); // step over nullTarget
+            code.getfield().setField(impl);
+            ifins = code.ifnonnull();
+            code.vreturn();
+            ifins.setTarget(code.aload().setThis());
+            code.getfield().setField(impl);
+            code.iload().setLocal(arrIdx);
+            code.constant().setNull();
+            code.aastore();
+            code.vreturn();
+        }
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    /**
+     * Add methods for loading and storing version data.
+     */
+    protected void addVersionMethods(BCClass bc) {
+        // void storeVersion(OpenJPAStateManager sm);
+        addBeanField(bc, "version", Object.class);
+        BCMethod meth = bc.declareMethod("storeVersion", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+        Code code = meth.getCode(true);
+
+        // version = sm.getVersion();
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.invokeinterface()
+            .setMethod(OpenJPAStateManager.class, "getVersion",
+                Object.class, null);
+        code.putfield().setField("version", Object.class);
+        code.vreturn();
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+
+        // void loadVersion(OpenJPAStateManager sm)
+        meth = bc.declareMethod("loadVersion", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+        code = meth.getCode(true);
+
+        // if (sm.getVersion() == null)
+        // 		sm.setVersion(version);
+        code.aload().setParam(0);
+        code.invokeinterface().setMethod(OpenJPAStateManager.class,
+            "getVersion", Object.class, null);
+        JumpInstruction ifins = code.ifnonnull();
+        code.aload().setParam(0);
+        code.aload().setThis();
+        code.getfield().setField("version", Object.class);
+        code.invokeinterface()
+            .setMethod(OpenJPAStateManager.class, "setVersion",
+                void.class, new Class[]{ Object.class });
+        ifins.setTarget(code.vreturn());
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    private void addLoadMethod(BCClass bc, ClassMetaData meta) {
+        // public void load(OpenJPAStateManager sm, FetchConfiguration fetch,
+        // 		Object context)
+        Code code = addLoadMethod(bc, false);
+        FieldMetaData[] fmds = meta.getFields();
+        Collection jumps = new LinkedList();
+        Collection jumps2;
+		
+        int local = code.getNextLocalsIndex();
+        code.constant().setNull();
+        code.astore().setLocal(local);
+        int inter = code.getNextLocalsIndex();
+        code.constant().setNull();
+        code.astore().setLocal(inter);
+
+        int objectCount = 0;
+        boolean intermediate;
+        for (int i = 0; i < fmds.length; i++) {
+            jumps2 = new LinkedList();
+            intermediate = usesIntermediate(fmds[i]);
+            setTarget(code.aload().setThis(), jumps);
+            // if (loaded.get(i)) or (!loaded.get(i)) depending on inter resp
+            code.getfield().setField("loaded", BitSet.class);
+            code.constant().setValue(i);
+            code.invokevirtual().setMethod(BitSet.class, "get",
+                boolean.class, new Class[]{ int.class });
+            jumps.add(code.ifne());
+
+            if (intermediate)
+                addLoadIntermediate(code, i, objectCount, jumps2, inter);
+            jumps2.add(code.go2());
+
+            // if (fetch.requiresFetch(fmds[i])!=FetchConfiguration.FETCH_NONE)
+            setTarget(code.aload().setParam(1), jumps);
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getMetaData", ClassMetaData.class, null);
+            code.constant().setValue(fmds[i].getIndex());
+            code.invokevirtual().setMethod(ClassMetaData.class,
+                "getField", FieldMetaData.class, new Class[]{int.class});
+            code.invokeinterface().setMethod (FetchConfiguration.class, 
+                "requiresFetch", int.class, new Class[]{FieldMetaData.class});
+            code.constant().setValue(FetchConfiguration.FETCH_NONE);
+            jumps2.add(code.ificmpeq());
+            addLoad(bc, code, fmds[i], objectCount, local, false);
+
+            jumps = jumps2;
+            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
+                objectCount++;
+        }
+        setTarget(code.vreturn(), jumps);
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    private void addLoadWithFieldsMethod(BCClass bc, ClassMetaData meta) {
+        Code code = addLoadMethod(bc, true);
+        // public void load(OpenJPAStateManager sm, BitSet fields,
+        // 		FetchConfiguration fetch, Object conn)
+        FieldMetaData[] fmds = meta.getFields();
+        Collection jumps = new LinkedList();
+        Collection jumps2;
+        int objectCount = 0;
+        boolean intermediate;
+        int local = code.getNextLocalsIndex();
+        code.constant().setNull();
+        code.astore().setLocal(local);
+        int inter = code.getNextLocalsIndex();
+        code.constant().setNull();
+        code.astore().setLocal(inter);
+
+        for (int i = 0; i < fmds.length; i++) {
+            jumps2 = new LinkedList();
+            intermediate = usesIntermediate(fmds[i]);
+            // if (fields.get(i))
+            // {
+            // 		if (loaded.get(i))
+            setTarget(code.aload().setParam(1), jumps);
+            code.constant().setValue(i);
+            code.invokevirtual().setMethod(BitSet.class, "get",
+                boolean.class, new Class[]{ int.class });
+            jumps2.add(code.ifeq());
+            code.aload().setThis();
+            code.getfield().setField("loaded", BitSet.class);
+            code.constant().setValue(i);
+            code.invokevirtual().setMethod(BitSet.class, "get",
+                boolean.class, new Class[]{ int.class });
+            if (intermediate)
+                jumps.add(code.ifeq());
+            else
+                jumps2.add(code.ifeq());
+
+            addLoad(bc, code, fmds[i], objectCount, local, true);
+            if (usesImplData(fmds[i])) {
+                // loadImplData(sm, i);
+                code.aload().setThis();
+                code.aload().setParam(0);
+                code.constant().setValue(i);
+                code.invokevirtual().setMethod("loadImplData", void.class,
+                    new Class[]{ OpenJPAStateManager.class, int.class });
+            }
+
+            // fields.clear(i);
+            code.aload().setParam(1);
+            code.constant().setValue(i);
+            code.invokevirtual().setMethod(BitSet.class, "clear", void.class,
+                new Class[] { int.class });
+
+            jumps2.add(code.go2());
+
+            if (intermediate)
+                setTarget(addLoadIntermediate
+                    (code, i, objectCount, jumps2, inter), jumps);
+
+            jumps = jumps2;
+            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
+                objectCount++;
+        }
+        setTarget(code.vreturn(), jumps);
+        code.calculateMaxStack();
+        code.calculateMaxLocals();
+    }
+
+    /**
+     * Declare and start the base load method.
+     */
+    private Code addLoadMethod(BCClass bc, boolean fields) {
+        Class[] args = null;
+        if (fields)
+            args = new Class[]{ OpenJPAStateManager.class, BitSet.class,
+                FetchConfiguration.class, Object.class };
+        else
+            args = new Class[]{ OpenJPAStateManager.class,
+                FetchConfiguration.class, Object.class };
+        BCMethod load = bc.declareMethod("load", void.class, args);
+        Code code = load.getCode(true);
+
+        //loadVersion(sm);
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.invokevirtual().setMethod("loadVersion", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+
+        //loadImplData(sm);
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.invokevirtual().setMethod("loadImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+        return code;
+    }
+
+    /**
+     * Add the field load.
+     */
+    private Instruction addLoad(BCClass bc, Code code, FieldMetaData fmd,
+        int objectCount, int local, boolean fields) {
+        int index = fmd.getIndex();
+        int typeCode = replaceType(fmd);
+        Instruction first;
+        if (typeCode < JavaTypes.OBJECT) {
+            // sm.store<type>(i, field<i>)
+            Class type = forType(fmd.getTypeCode());
+            first = code.aload().setParam(0);
+            code.constant().setValue(index);
+            code.aload().setThis();
+            code.getfield().setField(getFieldName(index), type);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "store" + StringUtils.capitalize(type.getName()),
+                void.class, new Class[]{ int.class, type });
+        } else {
+            // fmd = sm.getMetaData().getField(i);
+            int offset = fields ? 1 : 0;
+            first = code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getMetaData", ClassMetaData.class, null);
+            code.constant().setValue(fmd.getIndex());
+            code.invokevirtual().setMethod(ClassMetaData.class, "getField",
+                FieldMetaData.class, new Class[]{ int.class });
+            code.astore().setLocal(local);
+            // sm.storeField(i, toField(sm, fmd, objects[objectCount],
+            // 		fetch, context);
+            code.aload().setParam(0);
+            code.constant().setValue(index);
+            code.aload().setThis();
+            code.aload().setParam(0);
+            code.aload().setLocal(local);
+            code.aload().setThis();
+            code.getfield().setField("objects", Object[].class);
+            code.constant().setValue(objectCount);
+            code.aaload();
+            code.aload().setParam(1 + offset);
+            code.aload().setParam(2 + offset);
+            code.invokevirtual().setMethod(bc.getName(), "toField",
+                Object.class.getName(), toStrings(new Class[]{ 
+                OpenJPAStateManager.class, FieldMetaData.class,
+                Object.class, FetchConfiguration.class, Object.class }));
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "storeField", void.class,
+                new Class[]{ int.class, Object.class });
+        }
+        return first;
+    }
+
+    /**
+     * Load intermediate data if possible.
+     */
+    private Instruction addLoadIntermediate(Code code, int index,
+        int objectCount, Collection jumps2, int inter) {
+        // {
+        // 		Object inter = objects[objectCount];
+        Instruction first = code.aload().setThis();
+        code.getfield().setField("objects", Object[].class);
+        code.constant().setValue(objectCount);
+        code.aaload();
+        code.astore().setLocal(inter);
+        // 		if (inter != null && !sm.getLoaded().get(index))
+        code.aload().setLocal(inter);
+        jumps2.add(code.ifnull());
+        code.aload().setParam(0);
+        code.invokeinterface().setMethod(OpenJPAStateManager.class,
+            "getLoaded", BitSet.class, null);
+        code.constant().setValue(index);
+        code.invokevirtual().setMethod(BitSet.class, "get",
+            boolean.class, new Class[]{ int.class });
+        jumps2.add(code.ifne());
+        //			sm.setIntermediate(index, inter);
+        //	}  // end else
+        code.aload().setParam(0);
+        code.constant().setValue(index);
+        code.aload().setLocal(inter);
+        code.invokeinterface().setMethod(OpenJPAStateManager.class,
+            "setIntermediate", void.class,
+            new Class[]{ int.class, Object.class });
+        return first;
+    }
+
+    private void addStoreMethods(BCClass bc, ClassMetaData meta) {
+        // i.e. void store(OpenJPAStateManager sm, BitSet fields);
+        addStoreMethod(bc, meta, true);
+        // i.e. void store(OpenJPAStateManager sm);
+        addStoreMethod(bc, meta, false);
+    }
+
+    private void addStoreMethod(BCClass bc, ClassMetaData meta,
+        boolean fields) {
+        BCMethod store;
+        if (fields)
+            store = bc.declareMethod("store", void.class,
+                new Class[]{ OpenJPAStateManager.class, BitSet.class });
+        else
+            store = bc.declareMethod("store", void.class,
+                new Class[]{ OpenJPAStateManager.class });
+        Code code = store.getCode(true);
+
+        // initialize();
+        code.aload().setThis();
+        code.invokevirtual().setMethod("initialize", void.class, null);
+
+        // storeVersion(sm);
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.invokevirtual().setMethod("storeVersion", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+
+        // storeImplData(sm);
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.invokevirtual().setMethod("storeImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class });
+
+        FieldMetaData[] fmds = meta.getFields();
+        Collection jumps = new LinkedList();
+        int objectCount = 0;
+        for (int i = 0; i < fmds.length; i++) {
+            if (fields) {
+                //  if (fields != null && fields.get(index))
+                setTarget(code.aload().setParam(1), jumps);
+                jumps.add(code.ifnull());
+                code.aload().setParam(1);
+                code.constant().setValue(i);
+                code.invokevirtual().setMethod(BitSet.class, "get",
+                    boolean.class, new Class[]{ int.class });
+                jumps.add(code.ifeq());
+            } else {
+                // if (sm.getLoaded().get(index)))
+                setTarget(code.aload().setParam(0), jumps);
+                code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                    "getLoaded", BitSet.class, null);
+                code.constant().setValue(i);
+                code.invokevirtual().setMethod(BitSet.class, "get",
+                    boolean.class, new Class[]{ int.class });
+                jumps.add(code.ifeq());
+            }
+            addStore(bc, code, fmds[i], objectCount);
+            if (usesIntermediate(fmds[i])) {
+                JumpInstruction elseIns = code.go2();
+                // else if (!loaded.get(index))
+                setTarget(code.aload().setThis(), jumps);
+                jumps.add(elseIns);
+                code.getfield().setField("loaded", BitSet.class);
+                code.constant().setValue(i);
+                code.invokevirtual().setMethod(BitSet.class, "get",
+                    boolean.class, new Class[]{ int.class });
+                jumps.add(code.ifne());
+                // Object val = sm.getIntermediate(index);
+                // if (val != null)
+                // 		objects[objectCount] = val;
+                code.aload().setParam(0);
+                code.constant().setValue(i);
+                code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                    "getIntermediate", Object.class, new Class[]{ int.class });
+                int local = code.getNextLocalsIndex();
+                code.astore().setLocal(local);
+                code.aload().setLocal(local);
+                jumps.add(code.ifnull());
+                code.aload().setThis();
+                code.getfield().setField("objects", Object[].class);
+                code.constant().setValue(objectCount);
+                code.aload().setLocal(local);
+                code.aastore();
+            }
+            if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
+                objectCount++;
+        }
+        setTarget(code.vreturn(), jumps);
+        code.calculateMaxLocals();
+        code.calculateMaxStack();
+    }
+
+    private void addStore(BCClass bc, Code code, FieldMetaData fmd,
+        int objectCount) {
+        int typeCode = replaceType(fmd);
+        int index = fmd.getIndex();
+        if (typeCode < JavaTypes.OBJECT) {
+            Class type = forType(typeCode);
+            // field<i> = sm.fetch<Type>(index)
+            code.aload().setThis();
+            code.aload().setParam(0);
+            code.constant().setValue(index);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "fetch" + StringUtils.capitalize(type.getName()), type,
+                new Class[]{ int.class });
+            code.putfield().setField(getFieldName(index), type);
+            code.aload().setThis();
+            code.getfield().setField("loaded", BitSet.class);
+            code.constant().setValue(index);
+            code.invokevirtual().setMethod(BitSet.class, "set", void.class,
+                new Class[]{ int.class });
+        } else {
+            // Object val = toData(sm.getMetaData().getField(index),
+            // 		sm.fetchField(index, false), sm.getContext());
+            int local = code.getNextLocalsIndex();
+            code.aload().setThis();
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getMetaData", ClassMetaData.class, null);
+            code.constant().setValue(fmd.getIndex());
+            code.invokevirtual().setMethod(ClassMetaData.class,
+                "getField", FieldMetaData.class, new Class[]{ int.class });
+            code.aload().setParam(0);
+            code.constant().setValue(fmd.getIndex());
+            code.constant().setValue(false);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "fetchField", Object.class, new Class[]
+                { int.class, boolean.class });
+            code.aload().setParam(0);
+            code.invokeinterface().setMethod(OpenJPAStateManager.class,
+                "getContext", StoreContext.class, null);
+            code.invokevirtual().setMethod(bc.getName(), "toData",
+                Object.class.getName(), toStrings(new Class []{
+                FieldMetaData.class, Object.class, StoreContext.class }));
+            code.astore().setLocal(local);
+
+            // if (val == NULL) {
+            // 		val = null;
+            // 		loaded.clear(index);
+            // 	} else
+            // 		loaded.set(index);
+            // 	objects[objectCount] = val;
+            code.aload().setLocal(local);
+            code.getstatic().setField(AbstractPCData.class, "NULL",
+                Object.class);
+            JumpInstruction ifins = code.ifacmpne();
+            code.constant().setNull();
+            code.astore().setLocal(local);
+            code.aload().setThis();
+            code.getfield().setField("loaded", BitSet.class);
+            code.constant().setValue(index);
+            code.invokevirtual().setMethod(BitSet.class, "clear", void.class,
+                new Class[]{ int.class });
+            JumpInstruction go2 = code.go2();
+            ifins.setTarget(code.aload().setThis());
+            code.getfield().setField("loaded", BitSet.class);
+            code.constant().setValue(index);
+            code.invokevirtual().setMethod(BitSet.class, "set", void.class,
+                new Class[]{ int.class });
+            go2.setTarget(code.aload().setThis());
+            code.getfield().setField("objects", Object[].class);
+            code.constant().setValue(objectCount);
+            code.aload().setLocal(local);
+            code.aastore();
+        }
+        if (!usesImplData(fmd))
+            return;
+
+        // storeImplData(sm, i, loaded.get(i);
+        code.aload().setThis();
+        code.aload().setParam(0);
+        code.constant().setValue(index);
+        code.aload().setThis();
+        code.getfield().setField("loaded", BitSet.class);
+        code.constant().setValue(index);
+        code.invokevirtual().setMethod(BitSet.class, "get", boolean.class,
+            new Class[]{ int.class });
+        code.invokevirtual().setMethod("storeImplData", void.class,
+            new Class[]{ OpenJPAStateManager.class, int.class, boolean.class });
+    }
+
+    private void addNewEmbedded(BCClass bc) {
+        // void newEmbeddedPCData(OpenJPAStateManager embedded)
+        BCMethod meth = bc.declareMethod("newEmbeddedPCData", PCData.class,
+            new Class[]{ OpenJPAStateManager.class });
+        Code code = meth.getCode(true);
+        // return getStorageGenerator().generatePCData
+        // 		(sm.getId(), sm.getMetaData());
+        code.aload().setThis();
+        code.getfield().setField("storageGenerator", PCDataGenerator.class);
+        code.aload().setParam(0);
+        code.invokeinterface().setMethod(OpenJPAStateManager.class,
+            "getId", Object.class, null);
+        code.aload().setParam(0);
+        code.invokeinterface().setMethod(OpenJPAStateManager.class,
+            "getMetaData", ClassMetaData.class, null);
+        code.invokevirtual().setMethod(PCDataGenerator.class,
+            "generatePCData", PCData.class, new Class[]
+            { Object.class, ClassMetaData.class });
+        code.areturn();
+        code.calculateMaxLocals();
+        code.calculateMaxStack();
+    }
+
+    private void addGetData(BCClass bc) {
+        // return getObjectField(i);
+        BCMethod method = bc.declareMethod("getData", Object.class,
+            new Class[]{ int.class });
+        Code code = method.getCode(true);
+        code.aload().setThis();
+        code.iload().setParam(0);
+        code.invokevirtual().setMethod("getObject", Object.class,
+            new Class[]{ int.class });
+        code.areturn();
+        code.calculateMaxLocals();
+        code.calculateMaxStack();
+    }
+
+    /////////////
+    // Utilities
+    /////////////
+
+    /**
+     * Return a valid {@link JavaTypes} constant for the given field
+     */
+    protected int replaceType(FieldMetaData fmd) {
+        if (usesIntermediate(fmd))
+            return JavaTypes.OBJECT;
+        return fmd.getTypeCode();
+    }
+
+    /**
+     * Whether the given field uses a cacheable intermediate value.
+     */
+    protected boolean usesIntermediate(FieldMetaData fmd) {
+        return fmd.usesIntermediate();
+    }
+
+    /**
+     * Whether the given type might have cacheable class-level impl data.
+     */
+    protected boolean usesImplData(ClassMetaData meta) {
+        return true;
+    }
+
+    /**
+     * Whether the given field might have cacheable impl data.
+     */
+    protected boolean usesImplData(FieldMetaData fmd) {
+        return fmd.usesImplData() == null;
+    }
+
+    /**
+     * The number of fields with cacheable impl data.
+     */
+    private int countImplDataFields(ClassMetaData meta) {
+        FieldMetaData[] fmds = meta.getFields();
+        int count = 0;
+        for (int i = 0; i < fmds.length; i++)
+            if (usesImplData(fmds[i]))
+                count++;
+        return count;
+    }
+
+    /**
+     * Add method which defers to AbstractPCData.
+     */
+    protected void callAbstractPCData(BCClass bc, String name, Class retType,
+        Class[] args) {
+        BCMethod meth = bc.declareMethod(name, retType, args);
+        Code code = meth.getCode(true);
+        code.aload().setThis();
+        for (int i = 0; i < args.length; i++)
+            code.xload().setParam(i).setType(args[i]);
+        code.invokevirtual().setMethod(AbstractPCData.class, name, retType,
+            args);
+        if (!void.class.equals(retType))
+            code.xreturn().setType(retType);
+        code.calculateMaxLocals();
+        code.calculateMaxStack();
+    }
+
+    /**
+     * Set the collection of {@link JumpInstruction}s to the given instruction,
+     * clearing the collection in the process.
+     */
+    protected void setTarget(Instruction ins, Collection jumps) {
+        for (Iterator it = jumps.iterator(); it.hasNext();)
+            ((JumpInstruction) it.next()).setTarget(ins);
+        jumps.clear();
+    }
+
+    /**
+     * Transform the given array of classes to strings.
+     */
+    private static String[] toStrings(Class[] cls) {
+        String[] strings = new String[cls.length];
+        for (int i = 0; i < strings.length; i++)
+            strings[i] = cls[i].getName();
+        return strings;
+    }
+
+    /**
+     * Dynamic {@link PCData}s generated will implement this interface
+     * to simplify initialization.
+     */
+    public static interface DynamicPCData extends PCData {
+
+        public void setId(Object oid);
+
+        public PCDataGenerator getStorageGenerator();
+
+        public void setStorageGenerator (PCDataGenerator generator);
+	}
+}



Mime
View raw message