You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2008/03/25 04:38:02 UTC
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...
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);
+ }
+}