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 e62e7eaa7 OPENJPA-2911 addFieldImplDataMethods via ASM
e62e7eaa7 is described below

commit e62e7eaa7c656ee5c900395c5d450dc30d642467
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Mon Jul 24 16:21:52 2023 +0200

    OPENJPA-2911 addFieldImplDataMethods via ASM
---
 .../apache/openjpa/enhance/PCDataGenerator.java    | 359 +++++++++++----------
 1 file changed, 187 insertions(+), 172 deletions(-)

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 2a1d5dc96..d5a32f528 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
@@ -48,19 +48,18 @@ 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.LookupSwitchInsnNode;
 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.Instruction;
 import serp.bytecode.JumpInstruction;
-import serp.bytecode.LookupSwitchInstruction;
 import serp.bytecode.Project;
 
 /**
@@ -173,11 +172,11 @@ public class PCDataGenerator extends 
DynamicStorageGenerator {
         addImplDataMethods(bc, meta);
         addGetType(bc, meta);
         addVersionMethods(bc);
+        addFieldImplDataMethods(bc, meta);
 
         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);
@@ -373,163 +372,199 @@ public class PCDataGenerator extends 
DynamicStorageGenerator {
     /**
      * Add methods for loading and storing class-level impl data.
      */
-    private void addFieldImplDataMethods(BCClass bc, ClassMetaData meta) {
-        // public void loadImplData(OpenJPAStateManager sm, int i)
-        BCMethod meth = bc.declareMethod("loadImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class, int.class });
-        meth.makePrivate();
-        Code code = meth.getCode(true);
-
+    private void addFieldImplDataMethods(ClassNodeTracker cnt, ClassMetaData 
meta) {
+        ClassNode classNode = cnt.getClassNode();
         int count = countImplDataFields(meta);
-        BCField impl = null;
-        if (count == 0)
-            code.vreturn();
-        else {
-            // Object[] fieldImpl
-            impl = bc.declareField("fieldImpl", Object[].class);
-            impl.makePrivate();
+        FieldNode impl = null;
 
-            // if (fieldImpl != null)
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            JumpInstruction ifins = code.ifnonnull();
-            code.vreturn();
-
-            // Object obj = null;
-            int obj = code.getNextLocalsIndex();
-            ifins.setTarget(code.constant().setNull());
-            code.astore().setLocal(obj);
-
-            // establish switch target, then move before it
-            Instruction target = code.aload().setLocal(obj);
-            code.previous();
-
-            // switch(i)
-            code.iload().setParam(1);
-            LookupSwitchInstruction lswitch = code.lookupswitch();
-            FieldMetaData[] fields = meta.getFields();
-            int cacheable = 0;
-            for (int i = 0; i < fields.length; i++) {
-                if (!usesImplData(fields[i]))
-                    continue;
-                // case x: obj = fieldImpl[y]; break;
-                lswitch.addCase(i, code.aload().setThis());
-                code.getfield().setField(impl);
-                code.constant().setValue(cacheable++);
-                code.aaload();
-                code.astore().setLocal(obj);
-                code.go2().setTarget(target);
+        // public void loadImplData(OpenJPAStateManager sm, int i)
+        {
+            MethodNode meth = new MethodNode(Opcodes.ACC_PRIVATE,
+                                             "loadImplData",
+                                             
Type.getMethodDescriptor(Type.VOID_TYPE, 
Type.getType(OpenJPAStateManager.class), Type.INT_TYPE),
+                                             null, null);
+            classNode.methods.add(meth);
+            InsnList instructions = meth.instructions;
+
+            if (count == 0) {
+                instructions.add(new InsnNode(Opcodes.RETURN));
+            }
+            else {
+                // Object[] fieldImpl
+                impl = new FieldNode(Opcodes.ACC_PRIVATE, "fieldImpl", 
Type.getDescriptor(Object[].class), null, null);
+                classNode.fields.add(impl);
+
+                // if (fieldImpl != null)
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+
+                LabelNode lblEndIf = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, 
lblEndIf));
+                instructions.add(new InsnNode(Opcodes.RETURN));
+                instructions.add(lblEndIf);
+
+                // Object obj = null;
+                int objVarPos = AsmHelper.getLocalVarPos(meth);
+                instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+                instructions.add(new VarInsnNode(Opcodes.ASTORE, objVarPos));
+
+                LabelNode lblEnd = new LabelNode();
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2));
+                // switch(i)
+                LookupSwitchInsnNode lSwitch = new 
LookupSwitchInsnNode(lblEnd, null, null);
+                FieldMetaData[] fields = meta.getFields();
+                int cacheable = 0;
+                for (int i = 0; i < fields.length; i++) {
+                    if (!usesImplData(fields[i])) {
+                        continue;
+                    }
+
+                    // case x: obj = fieldImpl[y]; break;
+                    LabelNode lblCase = new LabelNode();
+                    instructions.add(lblCase);
+                    lSwitch.keys.add(i);
+                    lSwitch.labels.add(lblCase);
+                    instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+                    
instructions.add(AsmHelper.getLoadConstantInsn(cacheable++));
+                    instructions.add(new InsnNode(Opcodes.AALOAD));
+                    instructions.add(new VarInsnNode(Opcodes.ASTORE, 
objVarPos));
+                    instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEnd));
+                }
+                // 'default:' is empty
+
+                instructions.add(lblEnd);
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos));
+
+                // if (obj != null) return;
+                lblEndIf = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, 
lblEndIf));
+                instructions.add(new InsnNode(Opcodes.RETURN));
+
+                // end if
+                instructions.add(lblEndIf);
+
+                // sm.setImplData(index, impl);
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st 
parameter OpenJPAStateManager
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2nd 
parameter int
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos)); 
// the previously stored fieldImpl
+                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                    
Type.getInternalName(OpenJPAStateManager.class),
+                                                    "setImplData",
+                                                    
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, 
AsmHelper.TYPE_OBJECT)));
+                instructions.add(new InsnNode(Opcodes.RETURN));
             }
-            lswitch.setDefaultTarget(target);
-
-            // if (obj != null)
-            code.next();    // jump back over target
-            ifins = code.ifnonnull();
-            code.vreturn();
-
-            // sm.setImplData(index, impl);
-            ifins.setTarget(code.aload().setParam(0));
-            code.iload().setParam(1);
-            code.aload().setLocal(obj);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "setImplData", void.class,
-                new Class[]{ int.class, Object.class });
-            code.vreturn();
         }
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
 
         // void storeImplData(OpenJPAStateManager sm, int index, boolean 
loaded)
-        meth = bc.declareMethod("storeImplData", void.class,
-            new Class[]{ OpenJPAStateManager.class, int.class, boolean.class 
});
-        code = meth.getCode(true);
-        if (count == 0)
-            code.vreturn();
-        else {
-            // int arrIdx = -1;
-            // switch(index)
-            int arrIdx = code.getNextLocalsIndex();
-            code.constant().setValue(-1);
-            code.istore().setLocal(arrIdx);
-            code.iload().setParam(1);
-            LookupSwitchInstruction lswitch = code.lookupswitch();
-
-            // establish switch target, then move before it
-            Instruction switchTarget = code.iload().setLocal(arrIdx);
-            code.previous();
-
-            FieldMetaData[] fields = meta.getFields();
-            int cacheable = 0;
-            for (int i = 0; i < fields.length; i++) {
-                if (!usesImplData(fields[i]))
-                    continue;
-                // case x: arrIdx = y; break;
-                lswitch.addCase(i, code.constant().setValue(cacheable++));
-                code.istore().setLocal(arrIdx);
-                code.go2().setTarget(switchTarget);
+        {
+            MethodNode meth = new MethodNode(Opcodes.ACC_PRIVATE,
+                                             "storeImplData",
+                                             
Type.getMethodDescriptor(Type.VOID_TYPE,
+                                                                      
Type.getType(OpenJPAStateManager.class), Type.INT_TYPE, Type.BOOLEAN_TYPE),
+                                             null, null);
+            classNode.methods.add(meth);
+            InsnList instructions = meth.instructions;
+
+            if (count == 0) {
+                instructions.add(new InsnNode(Opcodes.RETURN));
+            }
+            else {
+                // int arrIdx = -1;
+                // switch(index)
+                int arrIdxVarPos = AsmHelper.getLocalVarPos(meth);
+                instructions.add(AsmHelper.getLoadConstantInsn(-1));
+                instructions.add(new VarInsnNode(Opcodes.ISTORE, 
arrIdxVarPos));
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2nd 
param int
+
+                LabelNode lblEnd = new LabelNode();
+                // switch(i)
+                LookupSwitchInsnNode lSwitch = new 
LookupSwitchInsnNode(lblEnd, null, null);
+
+                FieldMetaData[] fields = meta.getFields();
+                int cacheable = 0;
+                for (int i = 0; i < fields.length; i++) {
+                    if (!usesImplData(fields[i])) {
+                        continue;
+                    }
+
+                    // case x: arrIdx = y; break;
+                    LabelNode lblCase = new LabelNode();
+                    instructions.add(lblCase);
+                    lSwitch.keys.add(i);
+                    lSwitch.labels.add(lblCase);
+                    
instructions.add(AsmHelper.getLoadConstantInsn(cacheable++));
+                    instructions.add(new VarInsnNode(Opcodes.ISTORE, 
arrIdxVarPos));
+                    instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEnd));
+                }
+                // 'default:' is empty
+
+                instructions.add(lblEnd);
+
+                // if (arrIdx != -1)
+                instructions.add(AsmHelper.getLoadConstantInsn(-1));
+                LabelNode lblEndIf = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IF_ICMPNE, 
lblEndIf));
+                instructions.add(new InsnNode(Opcodes.RETURN));
+
+                // end if
+                instructions.add(lblEndIf);
+
+                // if (loaded)
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, 3)); // 3rd 
param, boolean
+                lblEndIf = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));
+
+                // Object obj = sm.getImplData(index)
+                int objVarPos = arrIdxVarPos+1;
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st 
param, OpenJPAStateManager
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2st 
param, int
+                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                                    
Type.getInternalName(OpenJPAStateManager.class),
+                                                    "getImplData",
+                                                    
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT, Type.INT_TYPE)));
+                instructions.add(new VarInsnNode(Opcodes.ASTORE, objVarPos));
+
+                // if (fieldImpl == null)
+                //     fieldImpl = new Object[fields];
+
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+
+                LabelNode lblEndIfNN = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, 
lblEndIfNN));
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(AsmHelper.getLoadConstantInsn(count));
+                instructions.add(new TypeInsnNode(Opcodes.ANEWARRAY, 
Type.getInternalName(Object.class)));
+                instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, 
classNode.name, impl.name, impl.desc));
+                instructions.add(lblEndIfNN);
+
+                // fieldImpl[arrIdx] = obj;
+                // return;
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, arrIdxVarPos));
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos));
+                instructions.add(new InsnNode(Opcodes.AASTORE));
+                instructions.add(new InsnNode(Opcodes.RETURN));
+
+                instructions.add(lblEndIf);
+
+                // if (fieldImpl != null)
+                //         fieldImpl[index] = null;
+                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+                lblEndIfNN = new LabelNode();
+                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, 
lblEndIfNN));
+                instructions.add(new InsnNode(Opcodes.RETURN));
+
+                instructions.add(lblEndIfNN);
+                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, 
classNode.name, impl.name, impl.desc));
+                instructions.add(new VarInsnNode(Opcodes.ILOAD, arrIdxVarPos));
+                instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+                instructions.add(new InsnNode(Opcodes.AASTORE));
+                instructions.add(new InsnNode(Opcodes.RETURN));
             }
-            lswitch.setDefaultTarget(switchTarget);
-            code.next();    // step over switch target
-
-            // if (arrIdx != -1)
-            code.constant().setValue(-1);
-            JumpInstruction ifins = code.ificmpne();
-            code.vreturn();
-
-            // create null target, then move before it
-            Instruction nullTarget = code.aload().setThis();
-            code.previous();
-
-            // if (loaded)
-            ifins.setTarget(code.iload().setParam(2));
-            code.ifeq().setTarget(nullTarget);
-
-            // Object obj = sm.getImplData(index)
-            int obj = code.getNextLocalsIndex();
-            code.aload().setParam(0);
-            code.iload().setParam(1);
-            code.invokeinterface().setMethod(OpenJPAStateManager.class,
-                "getImplData", Object.class, new Class[]{ int.class });
-            code.astore().setLocal(obj);
-
-            // if (obj != null)
-            code.aload().setLocal(obj);
-            code.ifnull().setTarget(nullTarget);
-
-            // if (fieldImpl == null)
-            //         fieldImpl = new Object[fields];
-            code.aload().setThis();
-            code.getfield().setField(impl);
-            ifins = code.ifnonnull();
-            code.aload().setThis();
-            code.constant().setValue(count);
-            code.anewarray().setType(Object.class);
-            code.putfield().setField(impl);
-
-            // fieldImpl[arrIdx] = obj;
-            // return;
-            ifins.setTarget(code.aload().setThis());
-            code.getfield().setField(impl);
-            code.iload().setLocal(arrIdx);
-            code.aload().setLocal(obj);
-            code.aastore();
-            code.vreturn();
-
-            // if (fieldImpl != null)
-            //         fieldImpl[index] = null;
-            code.next(); // step over nullTarget
-            code.getfield().setField(impl);
-            ifins = code.ifnonnull();
-            code.vreturn();
-            ifins.setTarget(code.aload().setThis());
-            code.getfield().setField(impl);
-            code.iload().setLocal(arrIdx);
-            code.constant().setNull();
-            code.aastore();
-            code.vreturn();
         }
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
     }
 
     /**
@@ -1093,24 +1128,6 @@ public class PCDataGenerator extends 
DynamicStorageGenerator {
         return count;
     }
 
-    /**
-     * Add method which defers to AbstractPCData.
-     */
-    protected void callAbstractPCData(BCClass bc, String name, Class<?> 
retType,
-        Class<?>[] args) {
-        BCMethod meth = bc.declareMethod(name, retType, args);
-        Code code = meth.getCode(true);
-        code.aload().setThis();
-        for (int i = 0; i < args.length; i++)
-            code.xload().setParam(i).setType(args[i]);
-        code.invokevirtual().setMethod(AbstractPCData.class, name, retType,
-            args);
-        if (!void.class.equals(retType))
-            code.xreturn().setType(retType);
-        code.calculateMaxLocals();
-        code.calculateMaxStack();
-    }
-
     /**
      * Set the collection of {@link JumpInstruction}s to the given instruction,
      * clearing the collection in the process.
@@ -1140,8 +1157,6 @@ public class PCDataGenerator extends 
DynamicStorageGenerator {
 
         void setId(Object oid);
 
-        PCDataGenerator getStorageGenerator();
-
         void setStorageGenerator (PCDataGenerator generator);
     }
 }

Reply via email to