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 <strub...@apache.org> 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:strub...@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; } 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)); }