This is an automated email from the ASF dual-hosted git repository.
struberg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git
The following commit(s) were added to refs/heads/master by this push:
new 60ccb2605 OPENJPA-2911 start removing Serp from PCDataGenerator
60ccb2605 is described below
commit 60ccb2605072307ddf123e499c458a34685d8e17
Author: Mark Struberg <[email protected]>
AuthorDate: Sun Jul 23 18:36:46 2023 +0200
OPENJPA-2911 start removing Serp from PCDataGenerator
wip
---
.../datacache/DataCachePCDataGenerator.java | 60 ++-
.../openjpa/enhance/DynamicStorageGenerator.java | 467 ++++++++++++---------
.../apache/openjpa/enhance/PCDataGenerator.java | 422 +++++++++++--------
.../org/apache/openjpa/util/InternalException.java | 4 +-
.../org/apache/openjpa/util/OpenJPAException.java | 3 +-
.../apache/openjpa/util/asm/ClassNodeTracker.java | 6 +-
.../enhance/TestDynamicStorageGenerator.java | 9 +-
7 files changed, 585 insertions(+), 386 deletions(-)
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
index 6a962ea0e..3d560aa60 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
@@ -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);
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
index e1b2b85b1..02e7c6c99 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
@@ -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();
-
- method = bc.declareMethod("getObjectCount", int.class, null);
- code = method.getCode(true);
- code.constant().setValue(objectCount);
- 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));
+
+ 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)));
+ }
+
+ if (lblEndIf != null) {
+ instructions.add(lblEndIf);
}
- Instruction ins = code.vreturn();
- if (ifins != null)
- ifins.setTarget(ins);
- code.calculateMaxLocals();
- code.calculateMaxStack();
+ 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;
+ }
}
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java
index 450b3a088..86ebf6c72 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java
@@ -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();
- // 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);
+ // find the default constructor
+ MethodNode defaultCt = classNode.methods.stream()
+ .filter(m -> m.name.equals("<init>") && m.desc.equals("()V"))
+ .findFirst()
+ .get();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ InsnList instructions = new InsnList();
+
+
+ // private BitSet loaded = new BitSet();
+ FieldNode loaded = addBeanField(bc, "loaded", BitSet.class);
+
+ 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);
-
- Collection<Instruction> 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();
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name,
typeField.name, typeField.desc));
+
+ LabelNode lblEndIfNN = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNN));
+
+ // 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));
+
+ instructions.add(lblEndIfNN);
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name,
typeField.name, typeField.desc));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+ }
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ 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 loadVersion(OpenJPAStateManager sm)
- meth = bc.declareMethod("loadVersion", void.class,
- new Class[]{ OpenJPAStateManager.class });
- code = meth.getCode(true);
+ // 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));
+ }
- // 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();
+ // void loadVersion(OpenJPAStateManager sm)
+ {
+ 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);
+ 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);
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/InternalException.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/InternalException.java
index 903566436..f30081599 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/InternalException.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/InternalException.java
@@ -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() {
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAException.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAException.java
index 15a89bd8d..8300d0788 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAException.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAException.java
@@ -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;
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
index acb615d7d..eb78edd02 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
@@ -27,7 +27,7 @@ import org.apache.xbean.asm9.tree.ClassNode;
* @author <a href="mailto:[email protected]">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;
}
diff --git
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestDynamicStorageGenerator.java
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestDynamicStorageGenerator.java
index a07a5cdb0..ef99af94b 100644
---
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestDynamicStorageGenerator.java
+++
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestDynamicStorageGenerator.java
@@ -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));
}