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; + } }