OPENJPA-2911 start removing Serp from PCDataGenerator

wip
This commit is contained in:
Mark Struberg 2023-07-23 18:36:46 +02:00
parent b04c985956
commit 60ccb26050
7 changed files with 580 additions and 381 deletions

View File

@ -29,10 +29,13 @@ import org.apache.openjpa.enhance.PCDataGenerator;
import org.apache.openjpa.kernel.AbstractPCData;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.lib.util.StringUtil;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import serp.bytecode.BCClass;
import serp.bytecode.BCField;
@ -40,6 +43,7 @@ import serp.bytecode.BCMethod;
import serp.bytecode.Code;
import serp.bytecode.Instruction;
import serp.bytecode.JumpInstruction;
import serp.bytecode.Project;
/**
* A {@link PCDataGenerator} instance which generates properly
@ -78,12 +82,18 @@ public class DataCachePCDataGenerator extends PCDataGenerator {
}
@Override
protected void decorate(BCClass bc, ClassMetaData meta) {
enhanceToData(bc);
enhanceToNestedData(bc);
replaceNewEmbeddedPCData(bc);
addSynchronization(bc);
addTimeout(bc);
protected void decorate(ClassNodeTracker cnt, ClassMetaData meta) {
//X TODO REMOVE
BCClass _bc = new Project().loadClass(cnt.getClassNode().name.replace("/", "."));
AsmHelper.readIntoBCClass(cnt, _bc);
enhanceToData(_bc);
enhanceToNestedData(_bc);
replaceNewEmbeddedPCData(_bc);
addSynchronization(_bc);
addTimeout(_bc);
cnt.setClassNode(AsmHelper.toClassNode(cnt.getProject(), _bc).getClassNode());
}
private void enhanceToData(BCClass bc) {
@ -185,6 +195,44 @@ public class DataCachePCDataGenerator extends PCDataGenerator {
code.calculateMaxStack();
}
/**
* Add a bean field of the given name and type.
*/
@Deprecated
private BCField addBeanField(BCClass bc, String name, Class type) {
if (name == null)
throw new IllegalArgumentException("name == null");
// private <type> <name>
BCField field = bc.declareField(name, type);
field.setAccessFlags(getFieldAccess());
name = StringUtil.capitalize(name);
// getter
String prefix = (type == boolean.class) ? "is" : "get";
BCMethod method = bc.declareMethod(prefix + name, type, null);
method.makePublic();
Code code = method.getCode(true);
code.aload().setThis();
code.getfield().setField(field);
code.xreturn().setType(type);
code.calculateMaxStack();
code.calculateMaxLocals();
// setter
method = bc.declareMethod("set" + name, void.class,
new Class[]{ type });
method.makePublic();
code = method.getCode(true);
code.aload().setThis();
code.xload().setParam(0).setType(type);
code.putfield().setField(field);
code.vreturn();
code.calculateMaxStack();
code.calculateMaxLocals();
return field;
}
private void addTimeout(BCClass bc) {
bc.declareInterface(DataCachePCData.class);
bc.declareInterface(Timed.class);

View File

@ -19,30 +19,40 @@
package org.apache.openjpa.enhance;
import java.lang.reflect.Constructor;
import java.security.AccessController;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.StringUtil;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.openjpa.util.asm.EnhancementClassLoader;
import org.apache.openjpa.util.asm.EnhancementProject;
import org.apache.xbean.asm9.Opcodes;
import org.apache.xbean.asm9.Type;
import org.apache.xbean.asm9.tree.ClassNode;
import org.apache.xbean.asm9.tree.FieldInsnNode;
import org.apache.xbean.asm9.tree.FieldNode;
import org.apache.xbean.asm9.tree.InsnList;
import org.apache.xbean.asm9.tree.InsnNode;
import org.apache.xbean.asm9.tree.JumpInsnNode;
import org.apache.xbean.asm9.tree.LabelNode;
import org.apache.xbean.asm9.tree.MethodInsnNode;
import org.apache.xbean.asm9.tree.MethodNode;
import org.apache.xbean.asm9.tree.TableSwitchInsnNode;
import org.apache.xbean.asm9.tree.TypeInsnNode;
import org.apache.xbean.asm9.tree.VarInsnNode;
import serp.bytecode.BCClass;
import serp.bytecode.BCClassLoader;
import serp.bytecode.BCField;
import serp.bytecode.BCMethod;
import serp.bytecode.Code;
import serp.bytecode.Constants;
import serp.bytecode.Instruction;
import serp.bytecode.JumpInstruction;
import serp.bytecode.LoadInstruction;
import serp.bytecode.Project;
import serp.bytecode.TableSwitchInstruction;
/**
* Factory for creating new {@link DynamicStorage} classes. Can be
* extended to decorate/modify the generated instances behavior.
*
* @author Steve Kim
* @author Mark Struberg rework to ASM
* @since 0.3.2.0
*/
public class DynamicStorageGenerator {
@ -95,11 +105,8 @@ public class DynamicStorageGenerator {
};
// the project/classloader for the classes.
private final Project _project = new Project();
private final BCClassLoader _loader =
AccessController.doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(
_project, AccessController.doPrivileged(J2DoPrivHelper
.getClassLoaderAction(DynamicStorage.class))));
private final EnhancementProject _project = new EnhancementProject();
private final EnhancementClassLoader _loader = new EnhancementClassLoader(_project, DynamicStorage.class.getClassLoader());
/**
* Generate a generic {@link DynamicStorage} instance with the given
@ -111,9 +118,9 @@ public class DynamicStorageGenerator {
return null;
String name = getClassName(obj);
BCClass bc = _project.loadClass(name);
ClassNodeTracker bc = _project.loadClass(name);
declareClasses(bc);
bc.addDefaultConstructor().makePublic();
addDefaultConstructor(bc);
int objectCount = declareFields(types, bc);
addFactoryMethod(bc);
@ -125,6 +132,26 @@ public class DynamicStorageGenerator {
return createFactory(bc);
}
private void addDefaultConstructor(ClassNodeTracker cnt) {
ClassNode classNode = cnt.getClassNode();
// find the default constructor
final boolean hasDefaultCt = classNode.methods.stream()
.anyMatch(m -> m.name.equals("<init>") && m.desc.equals("()V"));
if (!hasDefaultCt) {
MethodNode ctNode = new MethodNode(Opcodes.ACC_PUBLIC,
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE),
null, null);
ctNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
ctNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, classNode.superName,
"<init>", "()V"));
ctNode.instructions.add(new InsnNode(Opcodes.RETURN));
classNode.methods.add(ctNode);
}
}
/**
* Return a class name to use for the given user key. By default,
* returns the stringified key prefixed by PREFIX.
@ -138,7 +165,7 @@ public class DynamicStorageGenerator {
* {@link Constants}.
*/
protected int getFieldAccess() {
return Constants.ACCESS_PRIVATE;
return Opcodes.ACC_PRIVATE;
}
/**
@ -159,18 +186,17 @@ public class DynamicStorageGenerator {
/**
* Decorate the generated class.
*/
protected void decorate(Object obj, BCClass cls, int[] types) {
protected void decorate(Object obj, ClassNodeTracker cls, int[] types) {
}
/**
* Create a stub factory instance for the given class.
*/
protected DynamicStorage createFactory(BCClass bc) {
protected DynamicStorage createFactory(ClassNodeTracker bc) {
try {
Class cls = Class.forName(bc.getName(), false, _loader);
Class cls = Class.forName(bc.getClassNode().name.replace("/", "."), false, _loader);
Constructor cons = cls.getConstructor((Class[]) null);
DynamicStorage data = (DynamicStorage) cons.newInstance
((Object[]) null);
DynamicStorage data = (DynamicStorage) cons.newInstance((Object[]) null);
_project.clear(); // remove old refs
return data;
} catch (Throwable t) {
@ -181,74 +207,90 @@ public class DynamicStorageGenerator {
/**
* Add interface or superclass declarations to the generated class.
*/
protected void declareClasses(BCClass bc) {
protected void declareClasses(ClassNodeTracker bc) {
bc.declareInterface(DynamicStorage.class);
}
/**
* Implement the newInstance method.
*/
private void addFactoryMethod(BCClass bc) {
BCMethod method = bc.declareMethod("newInstance",
DynamicStorage.class, null);
Code code = method.getCode(true);
code.anew().setType(bc);
code.dup();
code.invokespecial().setMethod(bc.getName(), "<init>", "void", null);
code.areturn();
code.calculateMaxLocals();
code.calculateMaxStack();
private void addFactoryMethod(ClassNodeTracker bc) {
final ClassNode classNode = bc.getClassNode();
MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC,
"newInstance",
Type.getMethodDescriptor(Type.getType(DynamicStorage.class)),
null, null);
classNode.methods.add(method);
InsnList instructions = method.instructions;
instructions.add(new TypeInsnNode(Opcodes.NEW, classNode.name));
instructions.add(new InsnNode(Opcodes.DUP));
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
classNode.name,
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE)));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
/**
* Implement getFieldCount/getObjectCount.
*/
private void addFieldCount(BCClass bc, int[] types, int objectCount) {
BCMethod method = bc.declareMethod("getFieldCount", int.class, null);
Code code = method.getCode(true);
code.constant().setValue(types.length);
code.ireturn();
code.calculateMaxLocals();
code.calculateMaxStack();
private void addFieldCount(ClassNodeTracker bc, int[] types, int objectCount) {
final ClassNode classNode = bc.getClassNode();
MethodNode getFc = new MethodNode(Opcodes.ACC_PUBLIC,
"getFieldCount",
Type.getMethodDescriptor(Type.INT_TYPE),
null, null);
classNode.methods.add(getFc);
getFc.instructions.add(AsmHelper.getLoadConstantInsn(types.length));
getFc.instructions.add(new InsnNode(Opcodes.IRETURN));
method = bc.declareMethod("getObjectCount", int.class, null);
code = method.getCode(true);
code.constant().setValue(objectCount);
code.ireturn();
code.calculateMaxLocals();
code.calculateMaxStack();
MethodNode getOc = new MethodNode(Opcodes.ACC_PUBLIC,
"getObjectCount",
Type.getMethodDescriptor(Type.INT_TYPE),
null, null);
classNode.methods.add(getOc);
getOc.instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
getOc.instructions.add(new InsnNode(Opcodes.IRETURN));
}
/**
* Implement initialize.
*/
private void addInitialize(BCClass bc, int objectCount) {
BCMethod meth = bc.declareMethod("initialize", void.class, null);
Code code = meth.getCode(true);
JumpInstruction ifins = null;
private void addInitialize(ClassNodeTracker bc, int objectCount) {
final ClassNode classNode = bc.getClassNode();
MethodNode initMeth = new MethodNode(Opcodes.ACC_PUBLIC,
"initialize",
Type.getMethodDescriptor(Type.VOID_TYPE),
null, null);
classNode.methods.add(initMeth);
InsnList instructions = initMeth.instructions;
LabelNode lblEndIf = null;
if (objectCount > 0) {
// if (objects == null)
// objects = new Object[objectCount];
code.aload().setThis();
code.getfield().setField("objects", Object[].class);
ifins = code.ifnonnull();
code.aload().setThis();
code.constant().setValue(objectCount);
code.anewarray().setType(Object.class);
code.putfield().setField("objects", Object[].class);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
lblEndIf = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIf));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
instructions.add(new TypeInsnNode(Opcodes.ANEWARRAY, Type.getInternalName(Object.class)));
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
}
Instruction ins = code.vreturn();
if (ifins != null)
ifins.setTarget(ins);
code.calculateMaxLocals();
code.calculateMaxStack();
if (lblEndIf != null) {
instructions.add(lblEndIf);
}
instructions.add(new InsnNode(Opcodes.RETURN));
}
/**
* Declare the primitive fields and the object field.
*/
private int declareFields(int[] types, BCClass bc) {
bc.declareField("objects", Object[].class).makePrivate();
private int declareFields(int[] types, ClassNodeTracker bc) {
ClassNode classNode = bc.getClassNode();
classNode.fields.add(new FieldNode(Opcodes.ACC_PRIVATE, "objects", Type.getDescriptor(Object[].class), null, null));
int objectCount = 0;
Class type;
@ -257,8 +299,7 @@ public class DynamicStorageGenerator {
if (type == Object.class)
objectCount++;
else {
BCField field = bc.declareField(getFieldName(i), type);
field.setAccessFlags(getFieldAccess());
classNode.fields.add(new FieldNode(Opcodes.ACC_PRIVATE, getFieldName(i), Type.getDescriptor(type), null, null));
}
}
return objectCount;
@ -267,7 +308,7 @@ public class DynamicStorageGenerator {
/**
* Add all the typed set by index method.
*/
private void addSetMethods(BCClass bc, int[] types, int totalObjects) {
private void addSetMethods(ClassNodeTracker bc, int[] types, int totalObjects) {
for (int type : TYPES) {
addSetMethod(type, bc, types, totalObjects);
}
@ -276,77 +317,104 @@ public class DynamicStorageGenerator {
/**
* Add the typed set by index method.
*/
private void addSetMethod(int typeCode, BCClass bc, int[] types,
int totalObjects) {
private void addSetMethod(int typeCode, ClassNodeTracker bc, int[] types, int totalObjects) {
int handle = getCreateFieldMethods(typeCode);
if (handle == POLICY_EMPTY)
if (handle == POLICY_EMPTY) {
return;
}
Class type = forType(typeCode);
// public void set<Type> (int field, <type> val)
String name = Object.class.equals(type) ? "Object" : StringUtil.capitalize(type.getName());
name = "set" + name;
BCMethod method = bc.declareMethod(name, void.class,
new Class[]{ int.class, type });
method.makePublic();
Code code = method.getCode(true);
ClassNode classNode = bc.getClassNode();
MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC,
name,
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(type)),
null, null);
classNode.methods.add(method);
InsnList instructions = method.instructions;
// switch (field)
code.aload().setParam(0);
TableSwitchInstruction tabins = code.tableswitch();
tabins.setLow(0);
tabins.setHigh(types.length - 1);
Instruction defaultIns;
if (handle == POLICY_SILENT) {
defaultIns = code.vreturn();
}
else {
defaultIns = throwException(code, IllegalArgumentException.class);
}
tabins.setDefaultTarget(defaultIns);
instructions.add(new VarInsnNode(Opcodes.ILOAD, 1)); // switch on first parameter which is an int
LabelNode defLbl = new LabelNode();
TableSwitchInsnNode switchNd = new TableSwitchInsnNode(0, types.length - 1, defLbl);
instructions.add(switchNd);
int objectCount = 0;
for (int i = 0; i < types.length; i++) {
// default: throw new IllegalArgumentException
if (!isCompatible(types[i], typeCode)) {
tabins.addTarget(tabins.getDefaultTarget());
LabelNode caseLbl = new LabelNode();
switchNd.labels.add(caseLbl);
instructions.add(caseLbl);
instructions.add(getDefaultSetInstructions(handle));
continue;
}
tabins.addTarget(code.aload().setThis());
LabelNode caseLbl = new LabelNode();
switchNd.labels.add(caseLbl);
instructions.add(caseLbl);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
if (typeCode >= JavaTypes.OBJECT) {
// if (objects == null)
// objects = new Object[totalObjects];
code.aload().setThis();
code.getfield().setField("objects", Object[].class);
JumpInstruction ifins = code.ifnonnull();
code.aload().setThis();
code.constant().setValue(totalObjects);
code.anewarray().setType(Object.class);
code.putfield().setField("objects", Object[].class);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
LabelNode lblEndNonNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndNonNull));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(AsmHelper.getLoadConstantInsn(totalObjects));
instructions.add(new TypeInsnNode(Opcodes.ANEWARRAY, Type.getInternalName(Object.class)));
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
instructions.add(lblEndNonNull);
// objects[objectCount] = val;
ifins.setTarget(code.aload().setThis());
code.getfield().setField("objects", Object[].class);
code.constant().setValue(objectCount);
code.aload().setParam(1);
code.aastore();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd param
instructions.add(new InsnNode(Opcodes.AASTORE));
objectCount++;
} else {
// case i: fieldi = val;
LoadInstruction load = code.xload();
load.setType(type);
load.setParam(1);
code.putfield().setField("field" + i, type);
instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(type), 2)); // 2nd param is primitive
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, "field" + i, Type.getInternalName(type)));
}
// return
code.vreturn();
instructions.add(new InsnNode(Opcodes.RETURN));
}
code.calculateMaxLocals();
code.calculateMaxStack();
// default:
instructions.add(defLbl);
instructions.add(getDefaultSetInstructions(handle));
}
private static InsnList getDefaultSetInstructions(int handle) {
InsnList defaultInsns;
if (handle == POLICY_SILENT) {
defaultInsns = new InsnList();
defaultInsns.add(new InsnNode(Opcodes.RETURN));
}
else {
defaultInsns = AsmHelper.throwException(IllegalArgumentException.class);
}
return defaultInsns;
}
/**
* Add all typed get by index method for the given fields.
*/
private void addGetMethods(BCClass bc, int[] types) {
private void addGetMethods(ClassNodeTracker bc, int[] types) {
for (int type : TYPES) {
addGetMethod(type, bc, types);
}
@ -355,121 +423,139 @@ public class DynamicStorageGenerator {
/**
* Add typed get by index method.
*/
private void addGetMethod(int typeCode, BCClass bc, int[] types) {
private void addGetMethod(int typeCode, ClassNodeTracker bc, int[] types) {
int handle = getCreateFieldMethods(typeCode);
if (handle == POLICY_EMPTY)
if (handle == POLICY_EMPTY) {
return;
}
Class type = forType(typeCode);
// public <type> get<Type>Field (int field)
String name = Object.class.equals(type) ? "Object" :
StringUtil.capitalize(type.getName());
name = "get" + name;
BCMethod method = bc.declareMethod(name, type,
new Class[]{ int.class });
method.makePublic();
Code code = method.getCode(true);
String name = "get" + (Object.class.equals(type) ? "Object" : StringUtil.capitalize(type.getName()));
ClassNode classNode = bc.getClassNode();
MethodNode meth = new MethodNode(Opcodes.ACC_PUBLIC,
name,
Type.getMethodDescriptor(Type.getType(type), Type.INT_TYPE),
null, null);
classNode.methods.add(meth);
InsnList instructions = meth.instructions;
// switch (field)
code.aload().setParam(0);
TableSwitchInstruction tabins = code.tableswitch();
tabins.setLow(0);
tabins.setHigh(types.length - 1);
Instruction defaultIns = null;
if (typeCode == JavaTypes.OBJECT && handle == POLICY_SILENT) {
defaultIns = code.constant().setNull();
code.areturn();
} else
defaultIns = throwException
(code, IllegalArgumentException.class);
tabins.setDefaultTarget(defaultIns);
instructions.add(new VarInsnNode(Opcodes.ILOAD, 1)); // switch on first parameter which is an int
LabelNode defLbl = new LabelNode();
TableSwitchInsnNode switchNd = new TableSwitchInsnNode(0, types.length - 1, defLbl);
instructions.add(switchNd);
int objectCount = 0;
for (int i = 0; i < types.length; i++) {
// default: throw new IllegalArgumentException
if (!isCompatible(types[i], typeCode)) {
tabins.addTarget(tabins.getDefaultTarget());
LabelNode caseLbl = new LabelNode();
switchNd.labels.add(caseLbl);
instructions.add(caseLbl);
instructions.add(getDefaultGetInstructions(typeCode, handle));
continue;
}
tabins.addTarget(code.aload().setThis());
LabelNode caseLbl = new LabelNode();
switchNd.labels.add(caseLbl);
instructions.add(caseLbl);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
if (typeCode >= JavaTypes.OBJECT) {
// if (objects == null)
// return null;
// return objects[objectCount];
code.aload().setThis();
code.getfield().setField("objects", Object[].class);
JumpInstruction ifins = code.ifnonnull();
code.constant().setNull();
code.areturn();
ifins.setTarget(code.aload().setThis());
code.getfield().setField("objects", Object[].class);
code.constant().setValue(objectCount);
code.aaload();
code.areturn();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
LabelNode lblEndNonNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndNonNull));
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblEndNonNull);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
instructions.add(new InsnNode(Opcodes.AALOAD));
instructions.add(new InsnNode(Opcodes.ARETURN));
objectCount++;
} else {
// case i: return fieldi;
code.getfield().setField("field" + i, type);
code.xreturn().setType(type);
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "field" + i, Type.getInternalName(type)));
instructions.add(new InsnNode(AsmHelper.getReturnInsn(type)));
}
}
code.calculateMaxLocals();
code.calculateMaxStack();
// default:
instructions.add(defLbl);
instructions.add(getDefaultGetInstructions(typeCode, handle));
}
private static InsnList getDefaultGetInstructions(int typeCode, int handle) {
InsnList defaultInsns;
if (typeCode == JavaTypes.OBJECT && handle == POLICY_SILENT) {
defaultInsns = new InsnList();
defaultInsns.add(new InsnNode(Opcodes.ACONST_NULL));
defaultInsns.add(new InsnNode(Opcodes.ARETURN));
}
else {
defaultInsns = AsmHelper.throwException(IllegalArgumentException.class);
}
return defaultInsns;
}
/////////////
// Utilities
/////////////
/**
* Clear code associated with the given method signature, and return
* the empty code. Will return null if the method should be empty.
*/
protected Code replaceMethod(BCClass bc, String name, Class retType,
Class[] args, boolean remove) {
bc.removeDeclaredMethod(name, args);
BCMethod meth = bc.declareMethod(name, retType, args);
Code code = meth.getCode(true);
if (!remove)
return code;
code.xreturn().setType(retType);
code.calculateMaxStack();
code.calculateMaxLocals();
return null;
}
/**
* Add a bean field of the given name and type.
*/
protected BCField addBeanField(BCClass bc, String name, Class type) {
if (name == null)
protected FieldNode addBeanField(ClassNodeTracker bc, String name, Class type) {
if (name == null) {
throw new IllegalArgumentException("name == null");
}
ClassNode classNode = bc.getClassNode();
// private <type> <name>
BCField field = bc.declareField(name, type);
field.setAccessFlags(getFieldAccess());
FieldNode field = new FieldNode(getFieldAccess(), name, Type.getDescriptor(type), null, null);
classNode.fields.add(field);
name = StringUtil.capitalize(name);
// getter
String prefix = (type == boolean.class) ? "is" : "get";
BCMethod method = bc.declareMethod(prefix + name, type, null);
method.makePublic();
Code code = method.getCode(true);
code.aload().setThis();
code.getfield().setField(field);
code.xreturn().setType(type);
code.calculateMaxStack();
code.calculateMaxLocals();
{
String prefix = (type == boolean.class) ? "is" : "get";
MethodNode meth = new MethodNode(Opcodes.ACC_PUBLIC,
prefix + name,
Type.getMethodDescriptor(Type.getType(type)),
null, null);
classNode.methods.add(meth);
meth.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
meth.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, field.name, Type.getDescriptor(type)));
meth.instructions.add(new InsnNode(AsmHelper.getReturnInsn(type)));
}
// setter
method = bc.declareMethod("set" + name, void.class,
new Class[]{ type });
method.makePublic();
code = method.getCode(true);
code.aload().setThis();
code.xload().setParam(0).setType(type);
code.putfield().setField(field);
code.vreturn();
code.calculateMaxStack();
code.calculateMaxLocals();
{
MethodNode meth = new MethodNode(Opcodes.ACC_PUBLIC,
"set" + name,
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(type)),
null, null);
classNode.methods.add(meth);
meth.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
meth.instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(type), 1)); // value parameter
meth.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, Type.getDescriptor(type)));
meth.instructions.add(new InsnNode(Opcodes.RETURN));
}
return field;
}
@ -530,9 +616,10 @@ public class DynamicStorageGenerator {
*/
protected Class getWrapper(Class c) {
for (Class[] wrapper : WRAPPERS) {
if (wrapper[0].equals(c))
if (wrapper[0].equals(c)) {
return wrapper[1];
}
}
return c;
}
return c;
}
}

View File

@ -37,16 +37,31 @@ 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 org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.xbean.asm9.Opcodes;
import org.apache.xbean.asm9.Type;
import org.apache.xbean.asm9.tree.ClassNode;
import org.apache.xbean.asm9.tree.FieldInsnNode;
import org.apache.xbean.asm9.tree.FieldNode;
import org.apache.xbean.asm9.tree.InsnList;
import org.apache.xbean.asm9.tree.InsnNode;
import org.apache.xbean.asm9.tree.JumpInsnNode;
import org.apache.xbean.asm9.tree.LabelNode;
import org.apache.xbean.asm9.tree.MethodInsnNode;
import org.apache.xbean.asm9.tree.MethodNode;
import org.apache.xbean.asm9.tree.TypeInsnNode;
import org.apache.xbean.asm9.tree.VarInsnNode;
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;
import serp.bytecode.Project;
/**
* Generates {@link PCData} instances which avoid primitive wrappers
@ -54,10 +69,10 @@ import serp.bytecode.LookupSwitchInstruction;
* startup time.
*
* @author Steve Kim
* @author Mark Struberg rework to ASM
* @since 0.3.2
*/
public class PCDataGenerator
extends DynamicStorageGenerator {
public class PCDataGenerator extends DynamicStorageGenerator {
private static final Localizer _loc = Localizer.forPackage
(PCDataGenerator.class);
@ -130,10 +145,10 @@ public class PCDataGenerator
}
@Override
protected void declareClasses(BCClass bc) {
protected void declareClasses(ClassNodeTracker bc) {
super.declareClasses(bc);
bc.declareInterface(DynamicPCData.class);
bc.setSuperclass(AbstractPCData.class);
bc.getClassNode().superName = Type.getInternalName(AbstractPCData.class);
}
@Override
@ -149,52 +164,66 @@ public class PCDataGenerator
}
@Override
protected final void decorate(Object obj, BCClass bc, int[] types) {
protected final void decorate(Object obj, ClassNodeTracker 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);
addVersionMethods(bc);
BCClass _bc = new Project().loadClass(bc.getClassNode().name.replace("/", "."));
AsmHelper.readIntoBCClass(bc, _bc);
addFieldImplDataMethods(_bc, meta);
addLoadMethod(_bc, meta);
addLoadWithFieldsMethod(_bc, meta);
addStoreMethods(_bc, meta);
addNewEmbedded(_bc);
addGetData(_bc);
bc = AsmHelper.toClassNode(bc.getProject(), _bc);
decorate(bc, meta);
}
/**
* Apply additional decoration to generated class.
*/
protected void decorate(BCClass bc, ClassMetaData meta) {
protected void decorate(ClassNodeTracker 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 void enhanceConstructor(ClassNodeTracker bc) {
ClassNode classNode = bc.getClassNode();
// find the default constructor
MethodNode defaultCt = classNode.methods.stream()
.filter(m -> m.name.equals("<init>") && m.desc.equals("()V"))
.findFirst()
.get();
InsnList instructions = new InsnList();
// 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);
FieldNode loaded = addBeanField(bc, "loaded", BitSet.class);
code.calculateMaxStack();
code.calculateMaxLocals();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(BitSet.class)));
instructions.add(new InsnNode(Opcodes.DUP));
instructions.add(AsmHelper.getLoadConstantInsn(classNode.fields.size()));
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
Type.getInternalName(BitSet.class),
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, loaded.name, loaded.desc));
defaultCt.instructions.insertBefore(defaultCt.instructions.getLast(), instructions);
}
/**
@ -202,123 +231,143 @@ public class PCDataGenerator
* 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();
private void addGetType(ClassNodeTracker bc, ClassMetaData meta) {
ClassNode classNode = bc.getClassNode();
FieldNode typeField = new FieldNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, "type", Type.getDescriptor(Class.class), null, null);
classNode.fields.add(typeField);
// public Class getType() {
BCMethod getter = bc.declareMethod("getType", Class.class, null);
getter.makePublic();
Code code = getter.getCode(true);
MethodNode getter = new MethodNode(Opcodes.ACC_PUBLIC,
"getType",
Type.getMethodDescriptor(Type.getType(Class.class)),
null, null);
classNode.methods.add(getter);
InsnList instructions = getter.instructions;
// use name as constant filled with meta.getDescribedType().getName()
// if (type == null) {
// try {
// type = Class.forName
// (meta.getDescribedType().getName(), true,
// Thread.currentThread().getContextClassLoader());
// } catch (ClassNotFoundException cnfe) {
// throw new InternalException();
// }
// type = PCDataGenerator.getType(name)
// }
code.getstatic().setField(type);
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, typeField.name, typeField.desc));
Collection<Instruction> jumps = new LinkedList<>();
jumps.add(code.ifnonnull());
ExceptionHandler handler = code.addExceptionHandler();
LabelNode lblEndIfNN = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNN));
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();
// actual type = PCDataGenerator.getType(name)
instructions.add(AsmHelper.getLoadConstantInsn(meta.getDescribedType().getName()));
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
Type.getInternalName(PCDataGenerator.class),
"getType",
Type.getMethodDescriptor(Type.getType(Class.class), Type.getType(String.class))));
instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, typeField.name, typeField.desc));
code.calculateMaxStack();
code.calculateMaxLocals();
instructions.add(lblEndIfNN);
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, typeField.name, typeField.desc));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
public static Class<?> getType(String className) {
try {
return Class.forName(className, true, Thread.currentThread().getContextClassLoader());
}
catch (ClassNotFoundException cnfe) {
throw new InternalException();
}
}
/**
* Declare standard dynamic pcdata fields.
*/
private void addBaseFields(BCClass bc) {
private void addBaseFields(ClassNodeTracker bc) {
addBeanField(bc, "id", Object.class);
BCField field = addBeanField(bc, "storageGenerator",
PCDataGenerator.class);
field.setAccessFlags(field.getAccessFlags()
| Constants.ACCESS_TRANSIENT);
FieldNode field = addBeanField(bc, "storageGenerator", PCDataGenerator.class);
field.access |= 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);
private void addImplDataMethods(ClassNodeTracker bc, ClassMetaData meta) {
ClassNode classNode = bc.getClassNode();
BCField impl = null;
if (!usesImplData(meta))
code.vreturn();
// void storeImplData(OpenJPAStateManager);
MethodNode storeM = new MethodNode(Opcodes.ACC_PUBLIC,
"storeImplData",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class)),
null, null);
classNode.methods.add(storeM);
InsnList instructions = storeM.instructions;
FieldNode impl = null;
if (!usesImplData(meta)) {
instructions.add(new InsnNode(Opcodes.RETURN));
}
else {
// if (sm.isImplDataCacheable())
// setImplData(sm.getImplData());
// 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());
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"isImplDataCacheable",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE)));
LabelNode lblEndIfEq = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIfEq));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"getImplData",
Type.getMethodDescriptor(Type.getType(Object.class))));
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
classNode.name,
"setImplData",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class))));
instructions.add(lblEndIfEq);
instructions.add(new InsnNode(Opcodes.RETURN));
}
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();
MethodNode loadM = new MethodNode(Opcodes.ACC_PUBLIC,
"loadImplData",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class)),
null, null);
classNode.methods.add(loadM);
instructions = loadM.instructions;
if (!usesImplData(meta)) {
instructions.add(new InsnNode(Opcodes.RETURN));
}
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);
// sm.setImplData(impl, true);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"getImplData",
Type.getMethodDescriptor(Type.getType(Object.class))));
LabelNode lblEndIf = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIf));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
LabelNode lblEndIf2 = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIf2));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
instructions.add(AsmHelper.getLoadConstantInsn(true));
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"setImplData",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class), Type.BOOLEAN_TYPE)));
instructions.add(lblEndIf);
instructions.add(lblEndIf2);
instructions.add(new InsnNode(Opcodes.RETURN));
}
code.calculateMaxStack();
code.calculateMaxLocals();
}
/**
@ -448,7 +497,7 @@ public class PCDataGenerator
code.ifnull().setTarget(nullTarget);
// if (fieldImpl == null)
// fieldImpl = new Object[fields];
// fieldImpl = new Object[fields];
code.aload().setThis();
code.getfield().setField(impl);
ifins = code.ifnonnull();
@ -467,7 +516,7 @@ public class PCDataGenerator
code.vreturn();
// if (fieldImpl != null)
// fieldImpl[index] = null;
// fieldImpl[index] = null;
code.next(); // step over nullTarget
code.getfield().setField(impl);
ifins = code.ifnonnull();
@ -486,49 +535,67 @@ public class PCDataGenerator
/**
* 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);
protected void addVersionMethods(ClassNodeTracker bc) {
ClassNode classNode = bc.getClassNode();
// 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();
final FieldNode versionField = addBeanField(bc, "version", Object.class);
// void storeVersion(OpenJPAStateManager sm);
{
MethodNode storeMeth = new MethodNode(Opcodes.ACC_PUBLIC,
"storeVersion",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class)),
null, null);
classNode.methods.add(storeMeth);
InsnList instructions = storeMeth.instructions;
// version = sm.getVersion();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"getVersion",
Type.getMethodDescriptor(Type.getType(Object.class))));
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, versionField.name, versionField.desc));
instructions.add(new InsnNode(Opcodes.RETURN));
}
// void loadVersion(OpenJPAStateManager sm)
meth = bc.declareMethod("loadVersion", void.class,
new Class[]{ OpenJPAStateManager.class });
code = meth.getCode(true);
{
MethodNode loadMeth = new MethodNode(Opcodes.ACC_PUBLIC,
"loadVersion",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class)),
null, null);
classNode.methods.add(loadMeth);
InsnList instructions = loadMeth.instructions;
// 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();
// if (sm.getVersion() == null)
// sm.setVersion(version);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"getVersion",
Type.getMethodDescriptor(Type.getType(Object.class))));
LabelNode lblEndIf = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIf));
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, versionField.name, versionField.desc));
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(OpenJPAStateManager.class),
"setVersion",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class))));
instructions.add(lblEndIf);
instructions.add(new InsnNode(Opcodes.RETURN));
}
}
private void addLoadMethod(BCClass bc, ClassMetaData meta) {
// public void load(OpenJPAStateManager sm, FetchConfiguration fetch,
// Object context)
// Object context)
Code code = addLoadMethod(bc, false);
FieldMetaData[] fmds = meta.getFields();
Collection<Instruction> jumps = new LinkedList<>();
@ -584,7 +651,7 @@ public class PCDataGenerator
private void addLoadWithFieldsMethod(BCClass bc, ClassMetaData meta) {
Code code = addLoadMethod(bc, true);
// public void load(OpenJPAStateManager sm, BitSet fields,
// FetchConfiguration fetch, Object conn)
// FetchConfiguration fetch, Object conn)
FieldMetaData[] fmds = meta.getFields();
Collection<Instruction> jumps = new LinkedList<>();
Collection<Instruction> jumps2;
@ -602,7 +669,7 @@ public class PCDataGenerator
intermediate = usesIntermediate(fmds[i]);
// if (fields.get(i))
// {
// if (loaded.get(i))
// if (loaded.get(i))
setTarget(code.aload().setParam(1), jumps);
code.constant().setValue(i);
code.invokevirtual().setMethod(BitSet.class, "get",
@ -706,7 +773,7 @@ public class PCDataGenerator
FieldMetaData.class, new Class[]{ int.class });
code.astore().setLocal(local);
// sm.storeField(i, toField(sm, fmd, objects[objectCount],
// fetch, context);
// fetch, context);
code.aload().setParam(0);
code.constant().setValue(index);
code.aload().setThis();
@ -735,13 +802,13 @@ public class PCDataGenerator
private Instruction addLoadIntermediate(Code code, int index,
int objectCount, Collection<Instruction> jumps2, int inter) {
// {
// Object inter = objects[objectCount];
// 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))
// if (inter != null && !sm.getLoaded().get(index))
code.aload().setLocal(inter);
jumps2.add(code.ifnull());
code.aload().setParam(0);
@ -751,8 +818,8 @@ public class PCDataGenerator
code.invokevirtual().setMethod(BitSet.class, "get",
boolean.class, new Class[]{ int.class });
jumps2.add(code.ifne());
// sm.setIntermediate(index, inter);
// } // end else
// sm.setIntermediate(index, inter);
// } // end else
code.aload().setParam(0);
code.constant().setValue(index);
code.aload().setLocal(inter);
@ -769,8 +836,7 @@ public class PCDataGenerator
addStoreMethod(bc, meta, false);
}
private void addStoreMethod(BCClass bc, ClassMetaData meta,
boolean fields) {
private void addStoreMethod(BCClass bc, ClassMetaData meta, boolean fields) {
BCMethod store;
if (fields)
store = bc.declareMethod("store", void.class,
@ -832,7 +898,7 @@ public class PCDataGenerator
jumps.add(code.ifne());
// Object val = sm.getIntermediate(index);
// if (val != null)
// objects[objectCount] = val;
// objects[objectCount] = val;
code.aload().setParam(0);
code.constant().setValue(i);
code.invokeinterface().setMethod(OpenJPAStateManager.class,
@ -876,7 +942,7 @@ public class PCDataGenerator
new Class[]{ int.class });
} else {
// Object val = toData(sm.getMetaData().getField(index),
// sm.fetchField(index, false), sm.getContext());
// sm.fetchField(index, false), sm.getContext());
int local = code.getNextLocalsIndex();
code.aload().setThis();
code.aload().setParam(0);
@ -900,11 +966,11 @@ public class PCDataGenerator
code.astore().setLocal(local);
// if (val == NULL) {
// val = null;
// loaded.clear(index);
// } else
// loaded.set(index);
// objects[objectCount] = val;
// val = null;
// loaded.clear(index);
// } else
// loaded.set(index);
// objects[objectCount] = val;
code.aload().setLocal(local);
code.getstatic().setField(AbstractPCData.class, "NULL",
Object.class);
@ -950,7 +1016,7 @@ public class PCDataGenerator
new Class[]{ OpenJPAStateManager.class });
Code code = meth.getCode(true);
// return getStorageGenerator().generatePCData
// (sm.getId(), sm.getMetaData());
// (sm.getId(), sm.getMetaData());
code.aload().setThis();
code.getfield().setField("storageGenerator", PCDataGenerator.class);
code.aload().setParam(0);

View File

@ -26,10 +26,8 @@ import org.apache.openjpa.lib.util.Localizer.Message;
* @author Abe White
* @since 0.3.2
*/
public class InternalException
extends OpenJPAException {
public class InternalException extends OpenJPAException {
private static final long serialVersionUID = 1L;
public InternalException() {

View File

@ -35,8 +35,7 @@ import org.apache.openjpa.lib.util.Localizer.Message;
* @author Abe White
* @since 0.4.0
*/
public abstract class OpenJPAException
extends RuntimeException
public abstract class OpenJPAException extends RuntimeException
implements Serializable, ExceptionInfo {
private static final long serialVersionUID = 1L;

View File

@ -27,7 +27,7 @@ import org.apache.xbean.asm9.tree.ClassNode;
* @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
*/
public class ClassNodeTracker {
private final ClassNode classNode;
private ClassNode classNode;
private final ClassLoader cl;
private final EnhancementProject project;
@ -60,6 +60,10 @@ public class ClassNodeTracker {
return classNode;
}
public void setClassNode(ClassNode classNode) {
this.classNode = classNode;
}
public ClassLoader getClassLoader() {
return cl;
}

View File

@ -32,8 +32,7 @@ public class TestDynamicStorageGenerator
super(s, "enhancecactusapp");
}
public void testStorage()
throws Exception {
public void testStorage() throws Exception {
DynamicStorageGenerator gen = new DynamicStorageGenerator();
int[] types = new int[]{
@ -48,8 +47,7 @@ public class TestDynamicStorageGenerator
JavaTypes.STRING,
JavaTypes.OBJECT
};
DynamicStorage storage = gen.generateStorage(types,
"org.apache.openjpa.enhance.Test");
DynamicStorage storage = gen.generateStorage(types, "org.apache.openjpa.enhance.Test");
storage = storage.newInstance();
storage.setBoolean(0, true);
@ -71,8 +69,7 @@ public class TestDynamicStorageGenerator
assertEquals(4, storage.getShort(4));
assertEquals(5, storage.getLong(5));
assertTrue(6.59 < storage.getFloat(6) && 6.61 > storage.getFloat(6));
assertTrue(7.69 < storage.getDouble(7)
&& 7.71 > storage.getDouble(7));
assertTrue(7.69 < storage.getDouble(7) && 7.71 > storage.getDouble(7));
assertEquals("field8", storage.getObject(8));
assertEquals(date, storage.getObject(9));
}