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 fb20da5063e79bfc91214abdaff1acc718c69405
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Fri Jul 14 11:29:11 2023 +0200

    OPENJPA-2911 add clone support in ASM
---
 .../org/apache/openjpa/enhance/PCEnhancer.java     | 227 ++++++---------------
 1 file changed, 65 insertions(+), 162 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 b91bf4d15..a3593904e 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
@@ -604,10 +604,10 @@ public class PCEnhancer {
                 addAccessors(pc);
                 addAttachDetachCode();
                 addSerializationCode();
+                addCloningCode();
 
                 AsmHelper.readIntoBCClass(pc, _pc);
 
-                addCloningCode();
                 runAuxiliaryEnhancers();
                 return ENHANCE_PC;
             }
@@ -3723,29 +3723,23 @@ public class PCEnhancer {
         }
 
         AbstractInsnNode insn = method.instructions.getFirst();
-        do {
-            // skip to the next RETURN instruction
-            while (insn != null && insn.getOpcode() != Opcodes.RETURN) {
-                insn = insn.getNext();
-            }
-
-            if (insn != null) {
-                InsnList insns = new InsnList();
-                insns.add(new VarInsnNode(Opcodes.ILOAD, clearVarPos));
-                LabelNode lblEndIf = new LabelNode();
-                insns.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));
-                insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
-                insns.add(new InsnNode(Opcodes.ACONST_NULL));
-                insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
-                                             classNode.name,
-                                             PRE + "SetDetachedState",
-                                             
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class))));
-                insns.add(lblEndIf);
-                method.instructions.insertBefore(insn, insns);
-
-                insn = insn.getNext();
-            }
-        } while (insn != null);
+        // skip to the next RETURN instruction
+        while ((insn = searchNextInstruction(insn, i -> i.getOpcode() == 
Opcodes.RETURN)) != null) {
+            InsnList insns = new InsnList();
+            insns.add(new VarInsnNode(Opcodes.ILOAD, clearVarPos));
+            LabelNode lblEndIf = new LabelNode();
+            insns.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));
+            insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            insns.add(new InsnNode(Opcodes.ACONST_NULL));
+            insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                         classNode.name,
+                                         PRE + "SetDetachedState",
+                                         
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class))));
+            insns.add(lblEndIf);
+            method.instructions.insertBefore(insn, insns);
+
+            insn = insn.getNext();
+        }
 
         method.instructions.insert(instructions);
     }
@@ -4126,51 +4120,58 @@ public class PCEnhancer {
      * subclass, create the clone() method that clears the state manager
      * that may have been initialized in a super's clone() method.
      */
-    @Deprecated
     private void addCloningCode() {
-        if (_meta.getPCSuperclass() != null && !getCreateSubclass())
+        if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
             return;
+        }
+
+        ClassNode classNode = pc.getClassNode();
+
+        MethodNode cloneMeth = AsmHelper.getMethodNode(classNode, "clone", 
Object.class)
+                                        .orElse(null);
+
+        String superName = managedType.getClassNode().superName;
 
         // add the clone method if necessary
-        BCMethod clone = _pc.getDeclaredMethod("clone",
-                                               (String[]) null);
-        String superName = _managedType.getSuperclassName();
-        Code code = null;
-        if (clone == null) {
+        if (cloneMeth == null) {
             // add clone support for base classes
             // which also implement cloneable
-            boolean isCloneable = Cloneable.class.isAssignableFrom(
-                    _managedType.getType());
-            boolean extendsObject =
-                    superName.equals(Object.class.getName());
-            if (!isCloneable || (!extendsObject && !getCreateSubclass()))
+            boolean isCloneable = 
Cloneable.class.isAssignableFrom(_managedType.getType());
+            boolean extendsObject = superName.equals(Object.class.getName());
+            if (!isCloneable || (!extendsObject && !getCreateSubclass())) {
                 return;
+            }
 
-            if (!getCreateSubclass())
-                if (_log.isTraceEnabled())
-                    _log.trace(
-                            _loc.get("enhance-cloneable", 
_managedType.getName()));
+            if (!getCreateSubclass()) {
+                if (_log.isTraceEnabled()) {
+                    _log.trace(_loc.get("enhance-cloneable", 
_managedType.getName()));
+                }
+            }
 
             // add clone method
             // protected Object clone () throws CloneNotSupportedException
-            clone = _pc.declareMethod("clone", Object.class, null);
-            if (!setVisibilityToSuperMethod(clone))
-                clone.makeProtected();
-            clone.getExceptions(true).addException
-                    (CloneNotSupportedException.class);
-            code = clone.getCode(true);
+            cloneMeth = new MethodNode(0,
+                                       "clone",
+                                       Type.getMethodDescriptor(TYPE_OBJECT),
+                                       null,
+                                       new String[] 
{Type.getInternalName(CloneNotSupportedException.class)});
+            if (!setVisibilityToSuperMethod(cloneMeth)) {
+                cloneMeth.access |= Opcodes.ACC_PROTECTED;
+            }
 
             // return super.clone ();
-            loadManagedInstance(code, false);
-            code.invokespecial().setMethod(superName, "clone",
-                                           Object.class.getName(), null);
-            code.areturn();
+            cloneMeth.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // 
this
+            cloneMeth.instructions.add(new 
MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                          superName,
+                                                          "clone",
+                                                          
Type.getMethodDescriptor(TYPE_OBJECT)));
+            cloneMeth.instructions.add(new InsnNode(Opcodes.ARETURN));
         }
         else {
-            // get the clone method code
-            code = clone.getCode(false);
-            if (code == null)
+            if (cloneMeth.instructions.size() <=1) {
+                // if the clone method is basically empty
                 return;
+            }
         }
 
         // create template super.clone () instruction to match against
@@ -4180,17 +4181,19 @@ public class PCEnhancer {
 
         // find calls to the template instruction; on match
         // clone will be on stack
-        code.beforeFirst();
-        if (code.searchForward(template)) {
+        AbstractInsnNode insn = cloneMeth.instructions.getFirst();
+        while ((insn = searchNextInstruction(insn, i -> i.getOpcode() == 
Opcodes.INVOKESPECIAL &&
+                        i instanceof MethodInsnNode && ((MethodInsnNode) 
i).name.equals("clone"))
+                ) != null) {
             // ((<type>) clone).pcStateManager = null;
-            code.dup();
-            code.checkcast().setType(_pc);
-            code.constant().setNull();
-            code.putfield().setField(SM, SMTYPE);
+            InsnList instructions = new InsnList();
+            instructions.add(new InsnNode(Opcodes.DUP));
+            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, 
pc.getClassNode().name));
+            instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+            instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, 
classNode.name, SM, Type.getDescriptor(SMTYPE)));
 
-            // if modified, increase stack
-            code.calculateMaxStack();
-            code.calculateMaxLocals();
+            cloneMeth.instructions.insert(insn, instructions);
+            break;
         }
     }
 
@@ -4673,69 +4676,6 @@ public class PCEnhancer {
         return null;
     }
 
-
-    /**
-     * Adds to <code>code</code> the instructions to get field
-     * <code>attrName</code> declared in type <code>declarer</code>
-     * onto the top of the stack.
-     * <p>
-     * The instance to access must already be on the top of the
-     * stack when this is invoked.
-     */
-    @Deprecated
-    private void getfield(Code code, BCClass declarer, String attrName) {
-        if (declarer == null)
-            declarer = _managedType;
-
-        // first, see if we can convert the attribute name to a field name
-        String fieldName = toBackingFieldName(attrName);
-
-        // next, find the field in the managed type hierarchy
-        BCField field = null;
-        outer:
-        for (BCClass bc = _pc; bc != null; bc = bc.getSuperclassBC()) {
-            BCField[] fields = AccessController
-                    .doPrivileged(J2DoPrivHelper.getBCClassFieldsAction(bc,
-                                                                        
fieldName));
-            for (BCField bcField : fields) {
-                field = bcField;
-                // if we reach a field declared in this type, then this is the
-                // most-masking field, and is the one that we want.
-                if (bcField.getDeclarer() == declarer) {
-                    break outer;
-                }
-            }
-        }
-
-        if (getCreateSubclass() && code.getMethod().getDeclarer() == _pc
-                && (field == null || !field.isPublic())) {
-            // we're creating the subclass, not redefining the user type.
-
-            // Reflection.getXXX(this, Reflection.findField(...));
-            code.classconstant().setClass(declarer);
-            code.constant().setValue(fieldName);
-            code.constant().setValue(true);
-            code.invokestatic().setMethod(Reflection.class,
-                                          "findField", Field.class, new 
Class[]{
-                            Class.class, String.class, boolean.class});
-            Class type = _meta.getField(attrName).getDeclaredType();
-            try {
-                code.invokestatic().setMethod(
-                        getReflectionGetterMethod(type, Field.class));
-            }
-            catch (NoSuchMethodException e) {
-                // should never happen
-                throw new InternalException(e);
-            }
-            if (!type.isPrimitive() && type != Object.class)
-                code.checkcast().setType(type);
-        }
-        else {
-            code.getfield().setField(declarer.getName(), fieldName,
-                                     field.getType().getName());
-        }
-    }
-
     /**
      * Adds to <code>code</code> the instructions to set field
      * <code>attrName</code> declared in type <code>declarer</code>
@@ -4781,43 +4721,6 @@ public class PCEnhancer {
         }
     }
 
-    /**
-     * Adds to <code>code</code> the instructions to set field
-     * <code>attrName</code> declared in type <code>declarer</code>
-     * to the value of type <code>fieldType</code> on the top of the stack.
-     * <p>
-     * When this method is invoked, the value to load must
-     * already be on the top of the stack in <code>code</code>,
-     * and the instance to load into must be second.
-     */
-    @Deprecated
-    private void putfield(Code code, BCClass declarer, String attrName,
-                          Class fieldType) {
-        if (declarer == null)
-            declarer = _managedType;
-
-        String fieldName = toBackingFieldName(attrName);
-
-        if (getRedefine() || getCreateSubclass()) {
-            // Reflection.set(this, Reflection.findField(...), value);
-            code.classconstant().setClass(declarer);
-            code.constant().setValue(fieldName);
-            code.constant().setValue(true);
-            code.invokestatic().setMethod(Reflection.class,
-                                          "findField", Field.class, new 
Class[]{
-                            Class.class, String.class, boolean.class});
-            code.invokestatic().setMethod(Reflection.class, "set",
-                                          void.class,
-                                          new Class[]{
-                                                  Object.class,
-                                                  fieldType.isPrimitive() ? 
fieldType : Object.class,
-                                                  Field.class});
-        }
-        else {
-            code.putfield()
-                    .setField(declarer.getName(), fieldName, 
fieldType.getName());
-        }
-    }
 
     /**
      * If using property access, see if there is a different backing field

Reply via email to