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 279412c71a2b9ef93d3452db6640cc47b0eb0f7c
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Mon Jul 24 09:01:29 2023 +0200

    OPENJPA-2911 toNestedData in ASM
---
 .../datacache/DataCachePCDataGenerator.java        | 96 +++++++++++++---------
 .../org/apache/openjpa/util/asm/AsmHelper.java     | 29 +++++++
 2 files changed, 85 insertions(+), 40 deletions(-)

diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
index 35aadd372..6a65c5e59 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCachePCDataGenerator.java
@@ -18,9 +18,7 @@
  */
 package org.apache.openjpa.datacache;
 
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -95,12 +93,12 @@ public class DataCachePCDataGenerator extends 
PCDataGenerator {
     @Override
     protected void decorate(ClassNodeTracker cnt, ClassMetaData meta) {
         enhanceToData(cnt);
+        enhanceToNestedData(cnt);
 
         //X TODO REMOVE
         BCClass _bc = new 
Project().loadClass(cnt.getClassNode().name.replace("/", "."));
         AsmHelper.readIntoBCClass(cnt, _bc);
 
-        enhanceToNestedData(_bc);
         replaceNewEmbeddedPCData(_bc);
         addSynchronization(_bc);
         addTimeout(_bc);
@@ -149,25 +147,36 @@ public class DataCachePCDataGenerator extends 
PCDataGenerator {
         instructions.add(new InsnNode(Opcodes.ARETURN));
     }
 
-    private void enhanceToNestedData(BCClass bc) {
-        BCMethod meth = bc.declareMethod("toNestedData", Object.class,
-            new Class []{ ValueMetaData.class, Object.class,
-            StoreContext.class });
-        Code code = meth.getCode(true);
+    private void enhanceToNestedData(ClassNodeTracker cnt) {
+        ClassNode classNode = cnt.getClassNode();
+        MethodNode meth = new MethodNode(Opcodes.ACC_PUBLIC,
+                                         "toNestedData",
+                                         
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT,
+                                                                  
Type.getType(ValueMetaData.class),
+                                                                  
AsmHelper.TYPE_OBJECT,
+                                                                  
Type.getType(StoreContext.class)),
+                                         null, null);
+        classNode.methods.add(meth);
+        final InsnList instructions = meth.instructions;
 
         // if (val == null)
         //             return null;
-        code.aload().setParam(1);
-        JumpInstruction ifins = code.ifnonnull();
-        code.constant().setNull();
-        code.areturn();
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param, 
ValueMetaData
+
+        LabelNode lblEndIfNN = new LabelNode();
+        instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNN));
+        instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+        instructions.add(new InsnNode(Opcodes.ARETURN));
 
+        instructions.add(lblEndIfNN);
         // int type = vmd.getDeclaredTypeCode ();
-        ifins.setTarget(code.aload().setParam(0));
-        code.invokeinterface().setMethod(ValueMetaData.class,
-            "getDeclaredTypeCode", int.class, null);
-        int local = code.getNextLocalsIndex();
-        code.istore().setLocal(local);
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param, 
ValueMetaData
+        instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+                                            
Type.getInternalName(ValueMetaData.class),
+                                            "getDeclaredTypeCode",
+                                            
Type.getMethodDescriptor(Type.INT_TYPE)));
+        int varPos = AsmHelper.getLocalVarPos(meth);
+        instructions.add(new VarInsnNode(Opcodes.ISTORE, varPos));
 
         // if (type != JavaTypes.COLLECTION &&
         //        type != JavaTypes.MAP &&
@@ -175,29 +184,36 @@ public class DataCachePCDataGenerator extends 
PCDataGenerator {
         //        return super.toNestedData(type, val, ctx);
         //     else
         //             return NULL;
-        Collection jumps = new ArrayList(3);
-        code.iload().setLocal(local);
-        code.constant().setValue(JavaTypes.COLLECTION);
-        jumps.add(code.ificmpeq());
-        code.iload().setLocal(local);
-        code.constant().setValue(JavaTypes.MAP);
-        jumps.add(code.ificmpeq());
-        code.iload().setLocal(local);
-        code.constant().setValue(JavaTypes.ARRAY);
-        jumps.add(code.ificmpeq());
-        code.aload().setThis();
-        code.aload().setParam(0);
-        code.aload().setParam(1);
-        code.aload().setParam(2);
-        code.invokespecial().setMethod(AbstractPCData.class, "toNestedData",
-            Object.class, new Class[]{ ValueMetaData.class, Object.class,
-            StoreContext.class });
-        code.areturn();
-        setTarget(code.getstatic().setField
-            (AbstractPCData.class, "NULL", Object.class), jumps);
-        code.areturn();
-        code.calculateMaxStack();
-        code.calculateMaxLocals();
+        LabelNode lblEndIf = new LabelNode();
+        instructions.add(new VarInsnNode(Opcodes.ILOAD, varPos));
+        instructions.add(AsmHelper.getLoadConstantInsn(JavaTypes.COLLECTION));
+        instructions.add(new JumpInsnNode(Opcodes.IF_ICMPEQ, lblEndIf));
+        instructions.add(new VarInsnNode(Opcodes.ILOAD, varPos));
+        instructions.add(AsmHelper.getLoadConstantInsn(JavaTypes.MAP));
+        instructions.add(new JumpInsnNode(Opcodes.IF_ICMPEQ, lblEndIf));
+        instructions.add(new VarInsnNode(Opcodes.ILOAD, varPos));
+        instructions.add(AsmHelper.getLoadConstantInsn(JavaTypes.ARRAY));
+        instructions.add(new JumpInsnNode(Opcodes.IF_ICMPEQ, lblEndIf));
+
+        // if block
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param, 
ValueMetaData
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd param, 
Object
+        instructions.add(new VarInsnNode(Opcodes.ALOAD, 3)); // 3rd param, 
StoreContext
+        instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+                                            
Type.getInternalName(AbstractPCData.class),
+                                            "toNestedData",
+                                            
Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT,
+                                                                     
Type.getType(ValueMetaData.class),
+                                                                     
AsmHelper.TYPE_OBJECT,
+                                                                     
Type.getType(StoreContext.class))));
+        instructions.add(new InsnNode(Opcodes.ARETURN));
+
+        // end if
+        instructions.add(lblEndIf);
+        instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, 
Type.getInternalName(AbstractPCData.class),
+                                           "NULL", 
AsmHelper.TYPE_OBJECT.getDescriptor()));
+        instructions.add(new InsnNode(Opcodes.ARETURN));
     }
 
     private void replaceNewEmbeddedPCData(BCClass bc) {
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 4e7bc8ef8..121d3627d 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
@@ -708,4 +708,33 @@ public final class AsmHelper {
         }
     }
 
+    /**
+     * Calculate the next local variable position.
+     * For a non-static method the position 0 on the stack is the this pointer.
+     * After that there are all the method parameters.
+     * For a static method the method parameters begin at position zero.
+     * This method does calculate the first unused stack position which can be 
used for xLOAD/xSTORE opterations, e.g.
+     * <code>
+     * int nextVarPos = AsmHelper.getLocalVarPos(myMethodNode);
+     * instructions.add(AsmHelper.getLoadConstantInsn(4711));
+     * instructions.add(new VarInsnNode(Opcodes.ISTORE, nextVarPos);
+     * </code>
+     *
+     * @return the 0-based position on the stack at which the local variables 
can be located.
+     */
+    public static int getLocalVarPos(MethodNode meth) {
+        final Type[] paramTypes = Type.getArgumentTypes(meth.desc);
+
+        // stack position 0 is this pointer for non-static methods
+        // In other words: for a static method the first free stack location 
is 1,
+        // for non-static it is 2
+        int pos = ((meth.access & Opcodes.ACC_STATIC) > 0) ? 1 : 2;
+
+        // and now add the size of the parameters
+        for (Type paramType : paramTypes) {
+            pos += paramType.getSize();
+        }
+
+        return pos;
+    }
 }

Reply via email to