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 62b14584f OPENJPA-2911 Externalizable in ASM
62b14584f is described below

commit 62b14584fbf6781164f5a01f8784cf79a0e493a6
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Thu Jul 13 11:06:21 2023 +0200

    OPENJPA-2911 Externalizable in ASM
---
 .../org/apache/openjpa/enhance/PCEnhancer.java     | 770 +++++++++------------
 .../org/apache/openjpa/util/asm/AsmHelper.java     |   7 +-
 2 files changed, 329 insertions(+), 448 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 2ff67b469..377259dbe 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,6 +604,8 @@ public class PCEnhancer {
                 addAccessors(pc);
                 addAttachDetachCode();
 
+                AsmHelper.readIntoBCClass(pc, _pc);
+
                 addSerializationCode();
                 addCloningCode();
                 runAuxiliaryEnhancers();
@@ -1228,16 +1230,6 @@ public class PCEnhancer {
         }
     }
 
-    @Deprecated
-    private void addNotifyAccess(Code code, FieldMetaData fmd) {
-        // PCHelper.accessingField(this, <absolute-index>);
-        code.aload().setThis();
-        code.constant().setValue(fmd.getIndex());
-        code.invokestatic().setMethod(RedefinitionHelper.class,
-                                      "accessingField", void.class,
-                                      new Class[]{Object.class, int.class});
-    }
-
     /**
      * This must be called after setting the value in the object.
      *
@@ -1277,38 +1269,7 @@ public class PCEnhancer {
         methodNode.instructions.insert(currentInsn, insns);
         return insns.getLast();
     }
-    /**
-     * This must be called after setting the value in the object.
-     *
-     * @param val   the position in the local variable table where the
-     *              old value is stored
-     * @param param the parameter position containing the new value, or
-     *              -1 if the new value is unavailable and should therefore be 
looked
-     *              up.
-     */
-    @Deprecated
-    private void addNotifyMutation(Code code, FieldMetaData fmd, int val, int 
param)
-            throws NoSuchMethodException {
-        // PCHelper.settingField(this, <absolute-index>, old, new);
-        code.aload().setThis();
-        code.constant().setValue(fmd.getIndex());
-        Class type = fmd.getDeclaredType();
-        // we only have special signatures for primitives and Strings
-        if (!type.isPrimitive() && type != String.class)
-            type = Object.class;
-        code.xload().setLocal(val).setType(type);
-        if (param == -1) {
-            loadManagedInstance(code, false);
-            addGetManagedValueCode(code, fmd);
-        }
-        else {
-            code.xload().setParam(param).setType(type);
-        }
-        code.invokestatic().setMethod(RedefinitionHelper.class, "settingField",
-                                      void.class, new Class[]{
-                        Object.class, int.class, type, type
-                });
-    }
+
 
     /**
      * Return true if the given instruction accesses a field that is a backing
@@ -2525,62 +2486,6 @@ public class PCEnhancer {
         instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
-    /**
-     * Adds the appropriate load method for the given type and local
-     * index.
-     */
-    @Deprecated
-    private void loadLocalValue(Code code, int locidx, int typeCode) {
-        switch (typeCode) {
-            case JavaTypes.CHAR:
-            case JavaTypes.BYTE:
-            case JavaTypes.SHORT:
-            case JavaTypes.INT:
-                code.iload().setLocal(locidx);
-                break;
-            case JavaTypes.DOUBLE:
-                code.dload().setLocal(locidx);
-                break;
-            case JavaTypes.FLOAT:
-                code.fload().setLocal(locidx);
-                break;
-            case JavaTypes.LONG:
-                code.lload().setLocal(locidx);
-                break;
-            default:
-                code.aload().setLocal(locidx);
-                break;
-        }
-    }
-
-    /**
-     * Adds the appropriate store method for the given type and local
-     * index.
-     */
-    @Deprecated
-    private void storeLocalValue(Code code, int locidx, int typeCode) {
-        switch (typeCode) {
-            case JavaTypes.CHAR:
-            case JavaTypes.BYTE:
-            case JavaTypes.SHORT:
-            case JavaTypes.INT:
-                code.istore().setLocal(locidx);
-                break;
-            case JavaTypes.DOUBLE:
-                code.dstore().setLocal(locidx);
-                break;
-            case JavaTypes.FLOAT:
-                code.fstore().setLocal(locidx);
-                break;
-            case JavaTypes.LONG:
-                code.lstore().setLocal(locidx);
-                break;
-            default:
-                code.astore().setLocal(locidx);
-                break;
-        }
-    }
-
     /**
      * Add code to extract the id of the given primary key relation field for
      * setting into an objectid instance.
@@ -3406,19 +3311,6 @@ public class PCEnhancer {
         return instructions;
     }
 
-    /**
-     * Helper method to add the code necessary to throw the given
-     * exception type, sans message.
-     */
-    @Deprecated
-    private Instruction throwException(Code code, Class type) {
-        Instruction ins = code.anew().setType(type);
-        code.dup();
-        code.invokespecial().setMethod(type, "<init>", void.class, null);
-        code.athrow();
-        return ins;
-    }
-
     /**
      * Adds the PersistenceCapable interface to the class being
      * enhanced, and adds a default constructor for use by OpenJPA
@@ -4636,8 +4528,6 @@ public class PCEnhancer {
             addDetachedStateMethods(_meta.usesDetachedState() != 
Boolean.FALSE);
         }
 
-        AsmHelper.readIntoBCClass(pc, _pc);
-
         // if we detach on serialize, we also need to implement the
         // externalizable interface to write just the state for the fields
         // being detached
@@ -4962,44 +4852,63 @@ public class PCEnhancer {
     /**
      * Implement the externalizable interface to detach on serialize.
      */
-    private void addDetachExternalize(boolean parentDetachable,
-                                      boolean detachedState)
+    private void addDetachExternalize(boolean parentDetachable, boolean 
detachedState)
             throws NoSuchMethodException {
         // ensure that the declared default constructor is public
         // for externalization
-        BCMethod meth = _pc.getDeclaredMethod("<init>", (String[]) null);
-        if (!meth.isPublic()) {
-            if (_log.isWarnEnabled())
-                _log.warn(_loc.get("enhance-defcons-extern",
-                                   _meta.getDescribedType()));
-            meth.makePublic();
+        final MethodNode ctNode = pc.getClassNode().methods.stream()
+                .filter(m -> m.name.equals("<init>") && m.desc.equals("()V"))
+                .findAny()
+                .get();
+
+
+        if ((ctNode.access & Opcodes.ACC_PUBLIC) == 0) {
+            if (_log.isWarnEnabled()) {
+                _log.warn(_loc.get("enhance-defcons-extern", 
_meta.getDescribedType()));
+            }
+            ctNode.access = ctNode.access & ~Opcodes.ACC_PRIVATE & 
~Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC;
         }
+
         // declare externalizable interface
-        if (!Externalizable.class.isAssignableFrom(_meta.getDescribedType()))
-            _pc.declareInterface(Externalizable.class);
+        if (!Externalizable.class.isAssignableFrom(_meta.getDescribedType())) {
+            
pc.getClassNode().interfaces.add(Type.getInternalName(Externalizable.class));
+        }
 
         // make sure the user doesn't already have custom externalization or
         // serialization methods
-        Class[] input = new Class[]{ObjectInputStream.class};
-        Class[] output = new Class[]{ObjectOutputStream.class};
-        if (_managedType.getDeclaredMethod("readObject", input) != null
-                || _managedType.getDeclaredMethod("writeObject", output) != 
null)
+        String readObjectDesc = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(ObjectInputStream.class));
+        boolean hasReadObject = managedType.getClassNode().methods.stream()
+                .anyMatch(m -> m.name.equals("readObject") && 
m.desc.equals(readObjectDesc));
+
+        String writeObjectDesc = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(ObjectOutput.class));
+        boolean hasWriteObject = managedType.getClassNode().methods.stream()
+                .anyMatch(m -> m.name.equals("writeObject") && 
m.desc.equals(writeObjectDesc));
+
+        if (hasReadObject || hasWriteObject) {
             throw new UserException(_loc.get("detach-custom-ser", _meta));
-        input[0] = ObjectInput.class;
-        output[0] = ObjectOutput.class;
-        if (_managedType.getDeclaredMethod("readExternal", input) != null
-                || _managedType.getDeclaredMethod("writeExternal", output) != 
null)
+        }
+
+        String readExternalDesc = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(ObjectInput.class));
+        boolean hasReadExternal = managedType.getClassNode().methods.stream()
+                .anyMatch(m -> m.name.equals("readExternal") && 
m.desc.equals(readExternalDesc));
+
+        String writeExternalDesc = Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(ObjectInput.class));
+        boolean hasWriteExternal = managedType.getClassNode().methods.stream()
+                .anyMatch(m -> m.name.equals("writeExternal") && 
m.desc.equals(writeExternalDesc));
+
+        if (hasReadExternal || hasWriteExternal) {
             throw new UserException(_loc.get("detach-custom-extern", _meta));
+        }
 
         // create list of all unmanaged serializable fields
-        BCField[] fields = _managedType.getDeclaredFields();
-        Collection unmgd = new ArrayList(fields.length);
-        for (BCField field : fields) {
-            if (!field.isTransient() && !field.isStatic()
-                    && !field.isFinal()
-                    && !field.getName().startsWith(PRE)
-                    && _meta.getDeclaredField(field.getName()) == null)
+        final List<FieldNode> fields = managedType.getClassNode().fields;
+        List<FieldNode> unmgd = new ArrayList(fields.size());
+        for (FieldNode field : fields) {
+            if ((field.access & (Opcodes.ACC_TRANSIENT) | Opcodes.ACC_STATIC | 
Opcodes.ACC_FINAL) == 0
+                    && !field.name.startsWith(PRE)
+                    && _meta.getDeclaredField(field.name) == null) {
                 unmgd.add(field);
+            }
         }
 
         addReadExternal(parentDetachable, detachedState);
@@ -5011,16 +4920,18 @@ public class PCEnhancer {
     /**
      * Add custom readExternal method.
      */
-    @Deprecated
-    private void addReadExternal(boolean parentDetachable,
-                                 boolean detachedState)
+    private void addReadExternal(boolean parentDetachable, boolean 
detachedState)
             throws NoSuchMethodException {
-        Class[] inargs = new Class[]{ObjectInput.class};
-        BCMethod meth = _pc.declareMethod("readExternal", void.class, inargs);
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        exceps.addException(ClassNotFoundException.class);
-        Code code = meth.getCode(true);
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+        MethodNode readExternalMeth = new MethodNode(Opcodes.ACC_PUBLIC,
+                                                     "readExternal",
+                                                     methodDescriptor,
+                                                     null,
+                                                     new String[] 
{Type.getInternalName(IOException.class),
+                                                           
Type.getInternalName(ClassNotFoundException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(readExternalMeth);
+        InsnList instructions = readExternalMeth.instructions;
 
         // super.readExternal (in);
         // not sure if this works: this is depending on the order of the 
enhancement!
@@ -5028,146 +4939,171 @@ public class PCEnhancer {
         // the Externalizable at this point!
         Class<?> sup = _meta.getDescribedType().getSuperclass();
         if (!parentDetachable && Externalizable.class.isAssignableFrom(sup)) {
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(sup, "readExternal",
-                                           void.class, inargs);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                Type.getInternalName(sup),
+                                                "readExternal",
+                                                methodDescriptor));
         }
 
         // readUnmanaged (in);
-        loadManagedInstance(code, false);
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod(getType(_meta),
-                                       PRE + "ReadUnmanaged", void.class, 
inargs);
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                            
Type.getInternalName(getType(_meta)),
+                                            PRE + "ReadUnmanaged",
+                                            methodDescriptor));
 
         if (detachedState) {
             // pcSetDetachedState (in.readObject ());
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(ObjectInput.class, "readObject",
-                                             Object.class, null);
-            code.invokevirtual().setMethod(PRE + "SetDetachedState",
-                                           void.class, new 
Class[]{Object.class});
+            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(ObjectInput.class),
+                                                "readObject",
+                                                
Type.getMethodDescriptor(TYPE_OBJECT)));
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                                classNode.name,
+                                                PRE + "SetDetachedState",
+                                                
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
 
             // pcReplaceStateManager ((StateManager) in.readObject ());
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(ObjectInput.class, "readObject",
-                                             Object.class, null);
-            code.checkcast().setType(StateManager.class);
-            code.invokevirtual().setMethod(PRE + "ReplaceStateManager",
-                                           void.class, new 
Class[]{StateManager.class});
+            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(ObjectInput.class),
+                                                "readObject",
+                                                
Type.getMethodDescriptor(TYPE_OBJECT)));
+
+            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, 
Type.getInternalName(StateManager.class)));
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                                classNode.name,
+                                                PRE + "ReplaceStateManager",
+                                                
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(StateManager.class))));
         }
 
         addReadExternalFields();
 
         // readExternalFields(in.readObject ());
-        loadManagedInstance(code, false);
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("readExternalFields",
-                                       void.class, inargs);
-
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                            classNode.name,
+                                            "readExternalFields",
+                                            methodDescriptor));
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
-    @Deprecated
     private void addReadExternalFields() throws NoSuchMethodException {
-        Class<?>[] inargs = new Class[]{ObjectInput.class};
-        BCMethod meth = _pc.declareMethod("readExternalFields", void.class, 
inargs);
-        meth.setAccessFlags(Constants.ACCESS_PROTECTED);
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        exceps.addException(ClassNotFoundException.class);
-        Code code = meth.getCode(true);
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+        MethodNode readExternalMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+                                                     "readExternalFields",
+                                                     methodDescriptor,
+                                                     null,
+                                                     new String[] 
{Type.getInternalName(IOException.class),
+                                                             
Type.getInternalName(ClassNotFoundException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(readExternalMeth);
+        InsnList instructions = readExternalMeth.instructions;
 
         Class<?> sup = _meta.getPCSuperclass();
         if (sup != null) {
             //add a call to super.readExternalFields()
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(sup, "readExternalFields", 
void.class, inargs);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                Type.getInternalName(sup),
+                                                "readExternalFields",
+                                                methodDescriptor));
         }
 
         // read managed fields
         FieldMetaData[] fmds = _meta.getDeclaredFields();
         for (FieldMetaData fmd : fmds) {
             if (!fmd.isTransient()) {
-                readExternal(code, fmd.getName(),
-                             fmd.getDeclaredType(), fmd);
+                readExternal(classNode, instructions, fmd.getName(), 
Type.getType(fmd.getDeclaredType()), fmd);
             }
         }
-
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
     /**
      * Read unmanaged fields from the stream (pcReadUnmanaged).
      */
-    @Deprecated
-    private void addReadUnmanaged(Collection unmgd, boolean parentDetachable)
+    private void addReadUnmanaged(List<FieldNode> unmgd, boolean 
parentDetachable)
             throws NoSuchMethodException {
-        Class[] inargs = new Class[]{ObjectInput.class};
-        BCMethod meth = _pc.declareMethod(PRE + "ReadUnmanaged", void.class,
-                                          inargs);
-        meth.makeProtected();
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        exceps.addException(ClassNotFoundException.class);
-        Code code = meth.getCode(true);
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+        MethodNode readUnmanagedMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+                                                     PRE + "ReadUnmanaged",
+                                                     methodDescriptor,
+                                                     null,
+                                                     new String[] 
{Type.getInternalName(IOException.class),
+                                                             
Type.getInternalName(ClassNotFoundException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(readUnmanagedMeth);
+        InsnList instructions = readUnmanagedMeth.instructions;
 
         // super.readUnmanaged (in);
         if (parentDetachable) {
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(getType(_meta.
-                                                           
getPCSuperclassMetaData()), PRE + "ReadUnmanaged", void.class,
-                                           inargs);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                
Type.getInternalName(getType(_meta.getPCSuperclassMetaData())),
+                                                PRE + "ReadUnmanaged",
+                                                methodDescriptor));
         }
 
         // read declared unmanaged serializable fields
-        BCField field;
-        for (Object o : unmgd) {
-            field = (BCField) o;
-            readExternal(code, field.getName(), field.getType(), null);
+        for (FieldNode field : unmgd) {
+            readExternal(classNode, instructions, field.name, 
Type.getType(field.desc), null);
         }
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
     /**
      * Helper method to read a field from an externalization input stream.
      */
-    @Deprecated
-    private void readExternal(Code code, String fieldName, Class type,
-                              FieldMetaData fmd)
+    private void readExternal(ClassNode classNode, InsnList instructions, 
String fieldName, Type fieldType, FieldMetaData fmd)
             throws NoSuchMethodException {
+
+        if (fieldType == null) {
+            fieldType = Type.getType(fmd.getDeclaredType());
+        }
+        String typeName = fieldType.getClassName();
+        boolean isPrimitive = fieldType.getSort() != Type.OBJECT && 
fieldType.getSort() != Type.ARRAY;
+
         String methName;
-        if (type.isPrimitive()) {
-            methName = type.getName();
-            methName = methName.substring(0, 1).toUpperCase(Locale.ENGLISH)
-                    + methName.substring(1);
+        if (isPrimitive) {
+            methName = typeName.substring(0, 1).toUpperCase(Locale.ENGLISH)
+                    + typeName.substring(1);
             methName = "read" + methName;
         }
-        else
+        else {
             methName = "readObject";
+        }
 
         // <field> = in.read<type> ();
-        loadManagedInstance(code, false);
-        code.aload().setParam(0);
-        Class ret = (type.isPrimitive()) ? type : Object.class;
-        code.invokeinterface().setMethod(ObjectInput.class, methName,
-                                         ret, null);
-        if (!type.isPrimitive() && type != Object.class)
-            code.checkcast().setType(type);
-        if (fmd == null)
-            putfield(code, null, fieldName, type);
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        Type retType = isPrimitive ? fieldType : TYPE_OBJECT;
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                            
Type.getInternalName(ObjectInput.class),
+                                            methName,
+                                            
Type.getMethodDescriptor(retType)));
+
+        if (!isPrimitive && 
!fieldType.getClassName().equals(Object.class.getName())) {
+            instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, 
fieldType.getInternalName()));
+        }
+        if (fmd == null) {
+            Class<?> type = AsmHelper.getDescribedClass(pc.getClassLoader(), 
fieldType.getDescriptor());
+            if (type == null) {
+                throw new RuntimeException("Cannot Load class " + 
fieldType.getDescriptor());
+            }
+            putfield(classNode, instructions, null, fieldName, type);
+        }
         else {
-            addSetManagedValueCode(code, fmd);
+            addSetManagedValueCode(classNode, instructions, fmd);
             switch (fmd.getDeclaredTypeCode()) {
                 case JavaTypes.DATE:
                 case JavaTypes.ARRAY:
@@ -5177,16 +5113,19 @@ public class PCEnhancer {
                 case JavaTypes.CALENDAR:
                     // if (sm != null)
                     //   sm.proxyDetachedDeserialized (<index>);
-                    loadManagedInstance(code, false);
-                    code.getfield().setField(SM, SMTYPE);
-                    IfInstruction ifins = code.ifnull();
-                    loadManagedInstance(code, false);
-                    code.getfield().setField(SM, SMTYPE);
-                    code.constant().setValue(fmd.getIndex());
-                    code.invokeinterface().setMethod(SMTYPE,
-                                                     
"proxyDetachedDeserialized", void.class,
-                                                     new Class[]{int.class});
-                    ifins.setTarget(code.nop());
+                    instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // 
this
+                    instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+
+                    LabelNode lblEndIf = new LabelNode();
+                    instructions.add(new JumpInsnNode(Opcodes.IFNULL, 
lblEndIf));
+                    instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // 
this
+                    instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+                    
instructions.add(AsmHelper.getLoadConstantInsn(fmd.getIndex()));
+                    instructions.add(new 
MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                        
Type.getInternalName(SMTYPE),
+                                                        
"proxyDetachedDeserialized",
+                                                        
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
+                    instructions.add(lblEndIf);
             }
         }
     }
@@ -5194,182 +5133,211 @@ public class PCEnhancer {
     /**
      * Add custom writeExternal method.
      */
-    @Deprecated
-    private void addWriteExternal(boolean parentDetachable,
-                                  boolean detachedState)
+    private void addWriteExternal(boolean parentDetachable, boolean 
detachedState)
             throws NoSuchMethodException {
-        Class[] outargs = new Class[]{ObjectOutput.class};
-        BCMethod meth = _pc.declareMethod("writeExternal", void.class, 
outargs);
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        Code code = meth.getCode(true);
+
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+        MethodNode writeExternalMeth = new MethodNode(Opcodes.ACC_PUBLIC,
+                                                     "writeExternal",
+                                                     methodDescriptor,
+                                                     null,
+                                                     new String[] 
{Type.getInternalName(IOException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(writeExternalMeth);
+        InsnList instructions = writeExternalMeth.instructions;
+
 
         // super.writeExternal (out);
         Class sup = getType(_meta).getSuperclass();
         if (!parentDetachable && Externalizable.class.isAssignableFrom(sup)) {
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(sup, "writeExternal",
-                                           void.class, outargs);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                Type.getInternalName(sup),
+                                                "writeExternal",
+                                                methodDescriptor));
         }
 
         // writeUnmanaged (out);
-        loadManagedInstance(code, false);
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod(getType(_meta),
-                                       PRE + "WriteUnmanaged", void.class, 
outargs);
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                            
Type.getInternalName(getType(_meta)),
+                                            PRE + "WriteUnmanaged",
+                                            methodDescriptor));
+
+        LabelNode go2 = null;
 
-        JumpInstruction go2 = null;
         if (detachedState) {
             // if (sm != null)
             //   if (sm.writeDetached (out))
             //      return;
-            loadManagedInstance(code, false);
-            code.getfield().setField(SM, SMTYPE);
-            IfInstruction ifnull = code.ifnull();
-            loadManagedInstance(code, false);
-            code.getfield().setField(SM, SMTYPE);
-            code.aload().setParam(0);
-            code.invokeinterface().setMethod(SMTYPE, "writeDetached",
-                                             boolean.class, outargs);
-            go2 = code.ifeq();
-            code.vreturn();
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+
+            LabelNode endIfNull = new LabelNode();
+            instructions.add(new JumpInsnNode(Opcodes.IFNULL, endIfNull));
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                Type.getInternalName(SMTYPE),
+                                                "writeDetached",
+                                                
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(ObjectOutput.class))));
+
+            go2 = new LabelNode();
+            instructions.add(new JumpInsnNode(Opcodes.IFEQ, go2));
+            instructions.add(new InsnNode(Opcodes.RETURN));
 
             // else
             //   out.writeObject (pcGetDetachedState ());
-            Class[] objargs = new Class[]{Object.class};
-            ifnull.setTarget(code.aload().setParam(0));
-            loadManagedInstance(code, false);
-            code.invokevirtual().setMethod(PRE + "GetDetachedState",
-                                           Object.class, null);
-            code.invokeinterface().setMethod(ObjectOutput.class,
-                                             "writeObject", void.class, 
objargs);
-            //    out.writeObject (null) // StateManager
-            code.aload().setParam(0);
-            code.constant().setValue((Object) null);
-            code.invokeinterface().setMethod(ObjectOutput.class,
-                                             "writeObject", void.class, 
objargs);
+            instructions.add(endIfNull);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                                classNode.name,
+                                                PRE + "GetDetachedState",
+                                                
Type.getMethodDescriptor(TYPE_OBJECT)));
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                
Type.getInternalName(ObjectOutput.class),
+                                                "writeObject",
+                                                
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
+
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(AsmHelper.getLoadConstantInsn(null));
+            instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                
Type.getInternalName(ObjectOutput.class),
+                                                "writeObject",
+                                                
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
+        }
+        if (go2 != null) {
+            instructions.add(go2);
         }
-        if (go2 != null)
-            go2.setTarget(code.nop());
 
         addWriteExternalFields();
 
-        loadManagedInstance(code, false);
-        code.aload().setParam(0);
-        code.invokevirtual().setMethod("writeExternalFields",
-                                       void.class, outargs);
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+                                            classNode.name,
+                                            "writeExternalFields",
+                                            methodDescriptor));
 
         // return
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
 
-    @Deprecated
-    private void addWriteExternalFields()
-            throws NoSuchMethodException {
-        Class<?>[] outargs = new Class[]{ObjectOutput.class};
-        BCMethod meth = _pc.declareMethod("writeExternalFields", void.class, 
outargs);
-        meth.setAccessFlags(Constants.ACCESS_PROTECTED);
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        Code code = meth.getCode(true);
+    private void addWriteExternalFields() throws NoSuchMethodException {
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+        MethodNode writeExternalFieldsMeth = new 
MethodNode(Opcodes.ACC_PROTECTED,
+                                                     "writeExternalFields",
+                                                     methodDescriptor,
+                                                     null,
+                                                     new String[] 
{Type.getInternalName(IOException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(writeExternalFieldsMeth);
+        InsnList instructions = writeExternalFieldsMeth.instructions;
 
         Class<?> sup = _meta.getPCSuperclass();
         if (sup != null) {
-            // add a call to super.readExternalFields()
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(sup, "writeExternalFields", 
void.class, outargs);
+            // add a call to super.writeExternalFields()
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                Type.getInternalName(sup),
+                                                "writeExternalFields",
+                                                methodDescriptor));
         }
 
         FieldMetaData[] fmds = _meta.getDeclaredFields();
         for (FieldMetaData fmd : fmds) {
             if (!fmd.isTransient()) {
-                writeExternal(code, fmd.getName(),
-                              fmd.getDeclaredType(), fmd);
+                writeExternal(classNode, instructions, fmd.getName(),
+                              Type.getType(fmd.getDeclaredType()), fmd);
             }
         }
 
         // return
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
     /**
      * Write unmanaged fields to the stream (pcWriteUnmanaged).
      */
-    @Deprecated
-    private void addWriteUnmanaged(Collection unmgd, boolean parentDetachable)
+    private void addWriteUnmanaged(List<FieldNode> unmgd, boolean 
parentDetachable)
             throws NoSuchMethodException {
-        Class[] outargs = new Class[]{ObjectOutput.class};
-        BCMethod meth = _pc.declareMethod(PRE + "WriteUnmanaged", void.class,
-                                          outargs);
-        meth.makeProtected();
-        Exceptions exceps = meth.getExceptions(true);
-        exceps.addException(IOException.class);
-        Code code = meth.getCode(true);
+        final String methodDescriptor = 
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+        MethodNode writeUnmanagedMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+                                                      PRE + "WriteUnmanaged",
+                                                      methodDescriptor,
+                                                      null,
+                                                      new String[] 
{Type.getInternalName(IOException.class)});
+        final ClassNode classNode = pc.getClassNode();
+        classNode.methods.add(writeUnmanagedMeth);
+        InsnList instructions = writeUnmanagedMeth.instructions;
 
         // super.writeUnmanaged (out);
         if (parentDetachable) {
-            loadManagedInstance(code, false);
-            code.aload().setParam(0);
-            code.invokespecial().setMethod(getType(_meta.
-                                                           
getPCSuperclassMetaData()), PRE + "WriteUnmanaged", void.class,
-                                           outargs);
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+            instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+            instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                                
Type.getInternalName(getType(_meta.getPCSuperclassMetaData())),
+                                                PRE + "WriteUnmanaged",
+                                                methodDescriptor));
         }
 
         // write declared unmanaged serializable fields
-        BCField field;
-        for (Object o : unmgd) {
-            field = (BCField) o;
-            writeExternal(code, field.getName(), field.getType(), null);
+        for (FieldNode field : unmgd) {
+            writeExternal(classNode, instructions, field.name, 
Type.getType(field.desc), null);
         }
-        code.vreturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        instructions.add(new InsnNode(Opcodes.RETURN));
     }
 
     /**
      * Helper method to write a field to an externalization output stream.
      */
-    @Deprecated
-    private void writeExternal(Code code, String fieldName, Class type,
-                               FieldMetaData fmd)
+    private void writeExternal(ClassNode classNode, InsnList instructions, 
String fieldName, Type fieldType, FieldMetaData fmd)
             throws NoSuchMethodException {
+        String typeName = fieldType.getClassName();
+        boolean isPrimitive = fieldType.getSort() != Type.OBJECT && 
fieldType.getSort() != Type.ARRAY;
+
         String methName;
-        if (type.isPrimitive()) {
-            methName = type.getName();
-            methName = methName.substring(0, 1).toUpperCase(Locale.ENGLISH)
-                    + methName.substring(1);
+        if (isPrimitive) {
+            methName = typeName.substring(0, 1).toUpperCase(Locale.ENGLISH)
+                    + typeName.substring(1);
             methName = "write" + methName;
         }
-        else
+        else {
             methName = "writeObject";
+        }
 
         // out.write<type> (<field>);
-        code.aload().setParam(0);
-        loadManagedInstance(code, false);
-        if (fmd == null)
-            getfield(code, null, fieldName);
-        else
-            addGetManagedValueCode(code, fmd);
-        Class[] args = new Class[]{type};
-        if (type == byte.class || type == char.class || type == short.class)
-            args[0] = int.class;
-        else if (!type.isPrimitive())
-            args[0] = Object.class;
-        code.invokeinterface().setMethod(ObjectOutput.class, methName,
-                                         void.class, args);
-    }
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
 
-    @Deprecated
-    private void addGetManagedValueCode(Code code, FieldMetaData fmd)
-            throws NoSuchMethodException {
-        addGetManagedValueCode(code, fmd, true);
+        if (fmd == null) {
+            Class<?> type = AsmHelper.getDescribedClass(pc.getClassLoader(), 
fieldType.getDescriptor());
+            getfield(classNode, instructions, null, fieldName, type);
+        }
+        else {
+            addGetManagedValueCode(classNode, instructions, fmd, true);
+        }
+
+        String mdesc;
+        if (fieldType.getSort() == Type.BYTE || fieldType.getSort() == 
Type.CHAR || fieldType.getSort() == Type.SHORT) {
+            mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+        }
+        else if (!isPrimitive) {
+            mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
+        }
+        else {
+            mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, fieldType);
+        }
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                            
Type.getInternalName(ObjectOutput.class),
+                                            methName,
+                                            mdesc));
     }
 
 
@@ -5420,50 +5388,6 @@ public class PCEnhancer {
         }
     }
 
-    /**
-     * Load the field value specified by <code>fmd</code> onto the stack.
-     * Before this method is called, the object that the data should be loaded
-     * from will be on the top of the stack.
-     *
-     * @param fromSameClass if <code>true</code>, then <code>fmd</code> is
-     *                      being loaded from an instance of the same class as 
the current execution
-     *                      context. If <code>false</code>, then the instance 
on the top of the stack
-     *                      might be a superclass of the current execution 
context's 'this' instance.
-     */
-    @Deprecated
-    private void addGetManagedValueCode(Code code, FieldMetaData fmd,
-                                        boolean fromSameClass)
-            throws NoSuchMethodException {
-        // if redefining, then we must always reflect (or access the field
-        // directly if accessible), since the redefined methods will always
-        // trigger method calls to StateManager, even from internal direct-
-        // access usage. We could work around this by not redefining, and
-        // just do a subclass approach instead. But this is not a good option,
-        // since it would sacrifice lazy loading and efficient dirty tracking.
-
-        if (getRedefine() || isFieldAccess(fmd)) {
-            getfield(code, null, fmd.getName());
-        }
-        else if (getCreateSubclass()) {
-            // property access, and we're not redefining. If we're operating
-            // on an instance that is definitely the same type as 'this', then
-            // call superclass method to bypass tracking. Otherwise, reflect
-            // to both bypass tracking and avoid class verification errors.
-            if (fromSameClass) {
-                Method meth = (Method) fmd.getBackingMember();
-                code.invokespecial().setMethod(meth);
-            }
-            else {
-                getfield(code, null, fmd.getName());
-            }
-        }
-        else {
-            // regular enhancement + property access
-            Method meth = (Method) fmd.getBackingMember();
-            code.invokevirtual().setMethod(PRE + meth.getName(),
-                                           meth.getReturnType(), 
meth.getParameterTypes());
-        }
-    }
 
     /**
      * Store the given value into the field value specified
@@ -5540,36 +5464,6 @@ public class PCEnhancer {
         }
     }
 
-    /**
-     * Store the value at the top of the stack into the field value specified
-     * by <code>fmd</code>. Before this method is called, the data to load will
-     * be on the top of the stack and the object that the data should be loaded
-     * into will be second in the stack.
-     */
-    @Deprecated
-    private void addSetManagedValueCode(Code code, FieldMetaData fmd)
-        throws NoSuchMethodException {
-        // if redefining, then we must always reflect (or access the field
-        // directly if accessible), since the redefined methods will always
-        // trigger method calls to StateManager, even from internal direct-
-        // access usage. We could work around this by not redefining, and
-        // just do a subclass approach instead. But this is not a good option,
-        // since it would sacrifice lazy loading and efficient dirty tracking.
-
-        if (getRedefine() || isFieldAccess(fmd)) {
-            putfield(code, null, fmd.getName(), fmd.getDeclaredType());
-        } else if (getCreateSubclass()) {
-            // property access, and we're not redefining. invoke the
-            // superclass method to bypass tracking.
-            code.invokespecial().setMethod(_managedType.getType(),
-                getSetterName(fmd), void.class,
-                new Class[] { fmd.getDeclaredType() });
-        } else {
-            // regular enhancement + property access
-            code.invokevirtual().setMethod(PRE + getSetterName(fmd),
-                void.class, new Class[] { fmd.getDeclaredType() });
-        }
-    }
 
     /**
      * Add the {@link Instruction}s to load the instance to modify onto the
@@ -5762,22 +5656,6 @@ public class PCEnhancer {
         return meta.getDescribedType();
     }
 
-    /**
-     * Move code-related attributes from one method to another.
-     */
-    @Deprecated
-    private static void transferCodeAttributes(BCMethod from, BCMethod to) {
-        Code code = from.getCode(false);
-        if (code != null) {
-            to.addAttribute(code);
-            from.removeCode();
-        }
-
-        Exceptions exceps = from.getExceptions(false);
-        if (exceps != null)
-            to.addAttribute(exceps);
-    }
-
     /**
      * Usage: java org.apache.openjpa.enhance.PCEnhancer [option]*
      * &lt;class name | .java file | .class file | .jdo file&gt;+
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 b92da8438..6c7f8c919 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
@@ -610,15 +610,18 @@ public final class AsmHelper {
                 return long.class;
             case 'D':
                 return double.class;
+            case 'L':
+                if (typeDesc.charAt(typeDesc.length()-1) == ';')
+                return getClass(classLoader, typeDesc.substring(1, 
typeDesc.length()-1));
             default:
                 // some kind of class
                 return getClass(classLoader, typeDesc);
         }
     }
 
-    private static Class<?> getClass(ClassLoader classLoader, String typeName) 
{
+    public static Class<?> getClass(ClassLoader classLoader, String 
internalTypeName) {
         try {
-            return Class.forName(typeName.replace("/", "."), false, 
classLoader);
+            return Class.forName(internalTypeName.replace("/", "."), false, 
classLoader);
         }
         catch (NoClassDefFoundError | ClassNotFoundException e) {
             return null;

Reply via email to