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

commit 4b6a38ec1bea4ae3b961f3ecc2186d90a79a5c29
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Mon Jun 26 11:37:49 2023 +0200

    OPENJPA-2911 addNewObjectIdInstanceMethod in ASM
---
 .../org/apache/openjpa/enhance/PCEnhancer.java     | 357 +++++----------------
 .../org/apache/openjpa/util/asm/AsmHelper.java     |   8 +
 2 files changed, 95 insertions(+), 270 deletions(-)

diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java 
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
index e660b6419..7dfd011ab 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
@@ -1365,7 +1365,6 @@ public class PCEnhancer {
 
         addCopyFieldsMethod(pc.getClassNode());
 
-
         if (_meta.getPCSuperclass() == null || getCreateSubclass()) {
             addStockMethods();
             addGetVersionMethod();
@@ -1389,7 +1388,6 @@ public class PCEnhancer {
             addCopyKeyFieldsFromObjectIdMethod(true);
             addCopyKeyFieldsFromObjectIdMethod(false);
 
-
             if (_meta.hasAbstractPKField()) {
                 addGetIDOwningClass();
             }
@@ -1398,10 +1396,9 @@ public class PCEnhancer {
                 _log.warn(_loc.get("ID-field-in-embeddable-unsupported", 
_meta.toString()));
             }
 
-            AsmHelper.readIntoBCClass(pc, _pc);
-
             addNewObjectIdInstanceMethod(true);
             addNewObjectIdInstanceMethod(false);
+            AsmHelper.readIntoBCClass(pc, _pc);
         }
         else if (_meta.hasPKFieldsFromAbstractClass()) {
             addGetIDOwningClass();
@@ -2868,221 +2865,6 @@ public class PCEnhancer {
         instructions.add(lblGo2End);
     }
 
-    /**
-     * Add code to extract the id of the given primary key relation field for
-     * setting into an objectid instance.
-     */
-    @Deprecated
-    private void addExtractObjectIdFieldValueCode(Code code, FieldMetaData pk) 
{
-        // if (val != null)
-        //  val = ((PersistenceCapable) val).pcFetchObjectId();
-        int pc = code.getNextLocalsIndex();
-        code.astore().setLocal(pc);
-        code.aload().setLocal(pc);
-        JumpInstruction ifnull1 = code.ifnull();
-        code.aload().setLocal(pc);
-        code.checkcast().setType(PersistenceCapable.class);
-        if (!pk.getTypeMetaData().isOpenJPAIdentity())
-            code.invokeinterface().setMethod(PersistenceCapable.class,
-                                             PRE + "FetchObjectId", 
Object.class, null);
-        else
-            code.invokeinterface().setMethod(PersistenceCapable.class,
-                                             PRE + "NewObjectIdInstance", 
Object.class, null);
-
-        int oid = code.getNextLocalsIndex();
-        code.astore().setLocal(oid);
-        code.aload().setLocal(oid);
-        JumpInstruction ifnull2 = code.ifnull();
-
-        // for datastore / single-field identity:
-        // if (val != null)
-        //   val = ((OpenJPAId) val).getId();
-        ClassMetaData pkmeta = pk.getDeclaredTypeMetaData();
-        int pkcode = pk.getObjectIdFieldTypeCode();
-        Class pktype = pk.getObjectIdFieldType();
-        if (pkmeta.getIdentityType() == ClassMetaData.ID_DATASTORE
-                && pkcode == JavaTypes.LONG) {
-            code.aload().setLocal(oid);
-            code.checkcast().setType(Id.class);
-            code.invokevirtual().setMethod(Id.class, "getId",
-                                           long.class, null);
-        } else if (pkmeta.getIdentityType() == ClassMetaData.ID_DATASTORE) {
-            code.aload().setLocal(oid);
-        } else if (pkmeta.isOpenJPAIdentity()) {
-            switch (pkcode) {
-                case JavaTypes.BYTE_OBJ:
-                    code.anew().setType(Byte.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.BYTE:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(ByteId.class);
-                    code.invokevirtual().setMethod(ByteId.class, "getId",
-                                                   byte.class, null);
-                    if (pkcode == JavaTypes.BYTE_OBJ)
-                        code.invokespecial().setMethod(Byte.class, "<init>",
-                                                       void.class, new Class[] 
{byte.class});
-                    break;
-                case JavaTypes.CHAR_OBJ:
-                    code.anew().setType(Character.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.CHAR:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(CharId.class);
-                    code.invokevirtual().setMethod(CharId.class, "getId",
-                                                   char.class, null);
-                    if (pkcode == JavaTypes.CHAR_OBJ)
-                        code.invokespecial().setMethod(Character.class,
-                                                       "<init>", void.class, 
new Class[] {char.class});
-                    break;
-                case JavaTypes.DOUBLE_OBJ:
-                    code.anew().setType(Double.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.DOUBLE:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(DoubleId.class);
-                    code.invokevirtual().setMethod(DoubleId.class, "getId",
-                                                   double.class, null);
-                    if (pkcode == JavaTypes.DOUBLE_OBJ)
-                        code.invokespecial().setMethod(Double.class, "<init>",
-                                                       void.class, new 
Class[]{double.class});
-                    break;
-                case JavaTypes.FLOAT_OBJ:
-                    code.anew().setType(Float.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.FLOAT:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(FloatId.class);
-                    code.invokevirtual().setMethod(FloatId.class, "getId",
-                                                   float.class, null);
-                    if (pkcode == JavaTypes.FLOAT_OBJ)
-                        code.invokespecial().setMethod(Float.class, "<init>",
-                                                       void.class, new 
Class[]{float.class});
-                    break;
-                case JavaTypes.INT_OBJ:
-                    code.anew().setType(Integer.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.INT:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(IntId.class);
-                    code.invokevirtual().setMethod(IntId.class, "getId",
-                                                   int.class, null);
-                    if (pkcode == JavaTypes.INT_OBJ)
-                        code.invokespecial().setMethod(Integer.class, "<init>",
-                                                       void.class, new Class[] 
{int.class});
-                    break;
-                case JavaTypes.LONG_OBJ:
-                    code.anew().setType(Long.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.LONG:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(LongId.class);
-                    code.invokevirtual().setMethod(LongId.class, "getId",
-                                                   long.class, null);
-                    if (pkcode == JavaTypes.LONG_OBJ)
-                        code.invokespecial().setMethod(Long.class, "<init>",
-                                                       void.class, new Class[] 
{long.class});
-                    break;
-                case JavaTypes.SHORT_OBJ:
-                    code.anew().setType(Short.class);
-                    code.dup();
-                    // no break
-                case JavaTypes.SHORT:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(ShortId.class);
-                    code.invokevirtual().setMethod(ShortId.class, "getId",
-                                                   short.class, null);
-                    if (pkcode == JavaTypes.SHORT_OBJ)
-                        code.invokespecial().setMethod(Short.class, "<init>",
-                                                       void.class, new 
Class[]{short.class});
-                    break;
-                case JavaTypes.DATE:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(DateId.class);
-                    code.invokevirtual().setMethod(DateId.class, "getId",
-                                                   Date.class, null);
-                    if (pktype != Date.class) {
-                        // java.sql.Date.class
-                        code.checkcast().setType(pktype);
-                    }
-                    break;
-                case JavaTypes.STRING:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(StringId.class);
-                    code.invokevirtual().setMethod(StringId.class, "getId",
-                                                   String.class, null);
-                    break;
-                case JavaTypes.BIGDECIMAL:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(BigDecimalId.class);
-                    code.invokevirtual().setMethod(BigDecimalId.class, "getId",
-                                                   BigDecimal.class, null);
-                    break;
-                case JavaTypes.BIGINTEGER:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(BigIntegerId.class);
-                    code.invokevirtual().setMethod(BigIntegerId.class, "getId",
-                                                   BigInteger.class, null);
-                    break;
-                default:
-                    code.aload().setLocal(oid);
-                    code.checkcast().setType(ObjectId.class);
-                    code.invokevirtual().setMethod(ObjectId.class, "getId",
-                                                   Object.class, null);
-            }
-        } else if (pkmeta.getObjectIdType() != null) {
-            code.aload().setLocal(oid);
-            if (pkcode == JavaTypes.OBJECT) {
-                code.checkcast().setType(ObjectId.class);
-                code.invokevirtual().setMethod(ObjectId.class, "getId",
-                                               Object.class, null);
-            }
-            code.checkcast().setType(pktype);
-        } else
-            code.aload().setLocal(oid);
-        JumpInstruction go2 = code.go2();
-
-        // if (val == null)
-        //   val = <default>;
-        Instruction def;
-        switch (pkcode) {
-            case JavaTypes.BOOLEAN:
-                def = code.constant().setValue(false);
-                break;
-            case JavaTypes.BYTE:
-                def = code.constant().setValue((byte) 0);
-                break;
-            case JavaTypes.CHAR:
-                def = code.constant().setValue((char) 0);
-                break;
-            case JavaTypes.DOUBLE:
-                def = code.constant().setValue(0D);
-                break;
-            case JavaTypes.FLOAT:
-                def = code.constant().setValue(0F);
-                break;
-            case JavaTypes.INT:
-                def = code.constant().setValue(0);
-                break;
-            case JavaTypes.LONG:
-                def = code.constant().setValue(0L);
-                break;
-            case JavaTypes.SHORT:
-                def = code.constant().setValue((short) 0);
-                break;
-            default:
-                def = code.constant().setNull();
-        }
-        ifnull1.setTarget(def);
-        ifnull2.setTarget(def);
-        go2.setTarget(code.nop());
-    }
-
     /**
      * Adds the <code>pcCopyKeyFieldsFromObjectId</code> methods
      * to classes using application identity.
@@ -3409,91 +3191,112 @@ public class PCEnhancer {
      * Adds the pcNewObjectIdInstance method to classes using
      * application identity.
      */
-    private void addNewObjectIdInstanceMethod(boolean obj)
-            throws NoSuchMethodException {
+    private void addNewObjectIdInstanceMethod(boolean obj) throws 
NoSuchMethodException {
         // public Object pcNewObjectIdInstance ()
-        Class[] args = (obj) ? new Class[]{Object.class} : null;
-        BCMethod method = _pc.declareMethod(PRE + "NewObjectIdInstance",
-                                            Object.class, args);
-        Code code = method.getCode(true);
+        String mDesc = obj
+                ? Type.getMethodDescriptor(TYPE_OBJECT, TYPE_OBJECT)
+                : Type.getMethodDescriptor(TYPE_OBJECT);
+
+        MethodNode newOidMeth = new MethodNode(Opcodes.ACC_PUBLIC,
+                                               PRE + "NewObjectIdInstance",
+                                               mDesc,
+                                               null, null);
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(newOidMeth);
+        InsnList instructions = newOidMeth.instructions;
 
         Boolean usesClsString = usesClassStringIdConstructor();
         Class oidType = _meta.getObjectIdType();
         if (obj && usesClsString == null) {
             // throw new IllegalArgumentException (...);
-            String msg = _loc.get("str-cons", oidType,
-                                  _meta.getDescribedType()).getMessage();
-            code.anew().setType(IllegalArgumentException.class);
-            code.dup();
-            code.constant().setValue(msg);
-            code.invokespecial().setMethod(IllegalArgumentException.class,
-                                           "<init>", void.class, new 
Class[]{String.class});
-            code.athrow();
+            String msg = _loc.get("str-cons", oidType, 
_meta.getDescribedType()).getMessage();
 
-            code.calculateMaxStack();
-            code.calculateMaxLocals();
+            instructions.add(throwException(IllegalArgumentException.class, 
msg));
             return;
         }
 
         if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared()) {
             // new ObjectId (cls, oid)
-            code.anew().setType(ObjectId.class);
-            code.dup();
+            instructions.add(new TypeInsnNode(Opcodes.NEW, 
Type.getInternalName(ObjectId.class)));
+            instructions.add(new InsnNode(Opcodes.DUP));
+
             if (_meta.isEmbeddedOnly() || _meta.hasAbstractPKField()) {
-                code.aload().setThis();
-                code.invokevirtual().setMethod(PRE + "GetIDOwningClass",
-                                               Class.class, null);
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                                    classNode.name,
+                                                    PRE + "GetIDOwningClass",
+                                                    
Type.getMethodDescriptor(Type.getType(Class.class))));
             }
             else {
-                code.classconstant().setClass(getType(_meta));
+                
instructions.add(AsmHelper.getLoadConstantInsn(getType(_meta)));
             }
         }
 
         // new <oid class> ();
-        code.anew().setType(oidType);
-        code.dup();
+        instructions.add(new TypeInsnNode(Opcodes.NEW, 
Type.getInternalName(oidType)));
+        instructions.add(new InsnNode(Opcodes.DUP));
         if (_meta.isOpenJPAIdentity() || (obj && usesClsString == 
Boolean.TRUE)) {
             if ((_meta.isEmbeddedOnly()
                     && !(_meta.isEmbeddable() && _meta.getIdentityType() == 
ClassMetaData.ID_APPLICATION))
                     || _meta.hasAbstractPKField()) {
-                code.aload().setThis();
-                code.invokevirtual().setMethod(PRE + "GetIDOwningClass", 
Class.class, null);
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                                    classNode.name,
+                                                    PRE + "GetIDOwningClass",
+                                                    
Type.getMethodDescriptor(Type.getType(Class.class))));
             }
             else {
-                code.classconstant().setClass(getType(_meta));
+                
instructions.add(AsmHelper.getLoadConstantInsn(getType(_meta)));
             }
         }
+
+        String mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE);
         if (obj) {
-            code.aload().setParam(0);
-            code.checkcast().setType(String.class);
-            if (usesClsString == Boolean.TRUE)
-                args = new Class[]{Class.class, String.class};
-            else if (usesClsString == Boolean.FALSE)
-                args = new Class[]{String.class};
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, 
Type.getInternalName(String.class)));
+
+            if (usesClsString == Boolean.TRUE) {
+                mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(Class.class), Type.getType(String.class));
+            }
+            else if (usesClsString == Boolean.FALSE) {
+                mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(String.class));
+            }
         }
         else if (_meta.isOpenJPAIdentity()) {
             // new <type>Identity (XXX.class, <pk>);
-            loadManagedInstance(code, false);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
             FieldMetaData pk = _meta.getPrimaryKeyFields()[0];
-            addGetManagedValueCode(code, pk);
-            if (pk.getDeclaredTypeCode() == JavaTypes.PC)
-                addExtractObjectIdFieldValueCode(code, pk);
-            if (_meta.getObjectIdType() == ObjectId.class)
-                args = new Class[]{Class.class, Object.class};
-            else if (_meta.getObjectIdType() == Date.class)
-                args = new Class[]{Class.class, Date.class};
-            else
-                args = new Class[]{Class.class, pk.getObjectIdFieldType()};
+            addGetManagedValueCode(classNode, instructions, pk, true);
+            if (pk.getDeclaredTypeCode() == JavaTypes.PC) {
+                int nextFreeVarPos = 1;
+                addExtractObjectIdFieldValueCode(classNode, instructions, pk, 
nextFreeVarPos);
+            }
+
+            if (_meta.getObjectIdType() == ObjectId.class) {
+                mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(Class.class), Type.getType(Object.class));
+            }
+            else if (_meta.getObjectIdType() == Date.class) {
+                mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(Class.class), Type.getType(Date.class));
+            }
+            else {
+                mDescInit = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(Class.class), Type.getType(pk.getObjectIdFieldType()));
+            }
         }
 
-        code.invokespecial().setMethod(oidType, "<init>", void.class, args);
-        if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared())
-            code.invokespecial().setMethod(ObjectId.class, "<init>",
-                                           void.class, new 
Class[]{Class.class, Object.class});
-        code.areturn();
+        instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                            Type.getInternalName(oidType),
+                                            "<init>",
+                                            mDescInit));
 
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared()) {
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                
Type.getInternalName(ObjectId.class),
+                                                "<init>",
+                                                
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class), 
Type.getType(Object.class))));
+
+        }
+
+        instructions.add(new InsnNode(Opcodes.ARETURN));
     }
 
     /**
@@ -3579,13 +3382,27 @@ public class PCEnhancer {
      * exception type, sans message.
      */
     private InsnList throwException(Class type) {
+        return throwException(type, null);
+    }
+
+    /**
+     * Helper method to add the code necessary to throw the given
+     * exception type, sans message.
+     */
+    private InsnList throwException(Class type, String msg) {
         InsnList instructions = new InsnList();
         instructions.add(new TypeInsnNode(Opcodes.NEW, 
Type.getInternalName(type)));
         instructions.add(new InsnNode(Opcodes.DUP));
+        if (msg != null) {
+            instructions.add(AsmHelper.getLoadConstantInsn(msg));
+        }
+        String desc = msg != null
+                ? Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(String.class))
+                : Type.getMethodDescriptor(Type.VOID_TYPE);
         instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
                                             Type.getInternalName(type),
                                             "<init>",
-                                            
Type.getMethodDescriptor(Type.VOID_TYPE)));
+                                            desc));
         instructions.add(new InsnNode(Opcodes.ATHROW));
 
         return instructions;
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
index a87fde367..8f64b039e 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
@@ -119,6 +119,10 @@ public final class AsmHelper {
         ClassNode classNode = new ClassNode(Opcodes.ASM9);
         cr.accept(classNode, 0);
 
+        if ((classNode.version & 0xffff) < 49) {
+            classNode.version = 49;
+        }
+
         return new ClassNodeTracker(classNode, bcClass.getClassLoader());
     }
 
@@ -129,6 +133,10 @@ public final class AsmHelper {
     public static void readIntoBCClass(ClassNodeTracker cnt, BCClass bcClass) {
         // sadly package scoped
         try {
+            if (bcClass.getMajorVersion() < 49) {
+                bcClass.setMajorVersion(49);
+            }
+
             Method readMethod = BCClass.class.getDeclaredMethod("read", 
InputStream.class, ClassLoader.class);
 
             ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

Reply via email to