You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2023/07/25 08:15:47 UTC
[openjpa] 01/02: OPENJPA-2911 PCDataGenerator#store via ASM
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 8759f6fa7eebb4ed3f5a1cc7d0aa5e8c12197bbc
Author: Mark Struberg <st...@apache.org>
AuthorDate: Tue Jul 25 10:12:17 2023 +0200
OPENJPA-2911 PCDataGenerator#store via ASM
---
.../apache/openjpa/enhance/PCDataGenerator.java | 340 +++++++++++++--------
1 file changed, 206 insertions(+), 134 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 a2cbe55fc..df464fc5d 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
@@ -20,7 +20,6 @@ package org.apache.openjpa.enhance;
import java.util.BitSet;
import java.util.Collection;
-import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -175,11 +174,11 @@ public class PCDataGenerator extends DynamicStorageGenerator {
addFieldImplDataMethods(bc, meta);
addLoadMethod(bc, meta);
addLoadWithFieldsMethod(bc, meta);
+ addStoreMethods(bc, meta);
BCClass _bc = new Project().loadClass(bc.getClassNode().name.replace("/", "."));
AsmHelper.readIntoBCClass(bc, _bc);
- addStoreMethods(_bc, meta);
addNewEmbedded(_bc);
addGetData(_bc);
@@ -955,141 +954,198 @@ public class PCDataGenerator extends DynamicStorageGenerator {
instructions.add(lblEndIf);
}
- private void addStoreMethods(BCClass bc, ClassMetaData meta) {
+ private void addStoreMethods(ClassNodeTracker cnt, ClassMetaData meta) {
// i.e. void store(OpenJPAStateManager sm, BitSet fields);
- addStoreMethod(bc, meta, true);
+ addStoreMethod(cnt, meta, true);
// i.e. void store(OpenJPAStateManager sm);
- addStoreMethod(bc, meta, false);
+ addStoreMethod(cnt, meta, false);
}
- private void addStoreMethod(BCClass bc, ClassMetaData meta, boolean fields) {
- BCMethod store;
- if (fields)
- store = bc.declareMethod("store", void.class,
- new Class[]{ OpenJPAStateManager.class, BitSet.class });
- else
- store = bc.declareMethod("store", void.class,
- new Class[]{ OpenJPAStateManager.class });
- Code code = store.getCode(true);
+ private void addStoreMethod(ClassNodeTracker cnt, ClassMetaData meta, boolean fields) {
+
+ MethodNode store;
+ if (fields) {
+ store = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNCHRONIZED,
+ "store",
+ Type.getMethodDescriptor(Type.VOID_TYPE,
+ Type.getType(OpenJPAStateManager.class), Type.getType(BitSet.class)),
+ null, null);
+ }
+ else {
+ store = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNCHRONIZED,
+ "store",
+ Type.getMethodDescriptor(Type.VOID_TYPE,
+ Type.getType(OpenJPAStateManager.class)),
+ null, null);
+ }
+ ClassNode classNode = cnt.getClassNode();
+ classNode.methods.add(store);
+ InsnList instructions = store.instructions;
// initialize();
- code.aload().setThis();
- code.invokevirtual().setMethod("initialize", void.class, null);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "initialize",
+ Type.getMethodDescriptor(Type.VOID_TYPE)));
// storeVersion(sm);
- code.aload().setThis();
- code.aload().setParam(0);
- code.invokevirtual().setMethod("storeVersion", void.class,
- new Class[]{ OpenJPAStateManager.class });
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "storeVersion",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class))));
// storeImplData(sm);
- code.aload().setThis();
- code.aload().setParam(0);
- code.invokevirtual().setMethod("storeImplData", void.class,
- new Class[]{ OpenJPAStateManager.class });
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "storeImplData",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class))));
FieldMetaData[] fmds = meta.getFields();
- Collection<Instruction> jumps = new LinkedList<>();
int objectCount = 0;
for (int i = 0; i < fmds.length; i++) {
+ LabelNode lblEndIf = new LabelNode();
+
if (fields) {
// if (fields != null && fields.get(index))
- setTarget(code.aload().setParam(1), jumps);
- jumps.add(code.ifnull());
- code.aload().setParam(1);
- code.constant().setValue(i);
- code.invokevirtual().setMethod(BitSet.class, "get",
- boolean.class, new Class[]{ int.class });
- jumps.add(code.ifeq());
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd parameter, BitSet
+ instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndIf));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // 2nd parameter, BitSet
+ instructions.add(AsmHelper.getLoadConstantInsn(i));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "get",
+ Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.INT_TYPE)));
+ instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));
} else {
// if (sm.getLoaded().get(index)))
- setTarget(code.aload().setParam(0), jumps);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "getLoaded", BitSet.class, null);
- code.constant().setValue(i);
- code.invokevirtual().setMethod(BitSet.class, "get",
- boolean.class, new Class[]{ int.class });
- jumps.add(code.ifeq());
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter, OpenJPAStateManager
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(OpenJPAStateManager.class),
+ "getLoaded",
+ Type.getMethodDescriptor(Type.getType(BitSet.class))));
+ instructions.add(AsmHelper.getLoadConstantInsn(i));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "get",
+ Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.INT_TYPE)));
+ instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));
}
- addStore(bc, code, fmds[i], objectCount);
+ addStore(classNode, store, instructions, fmds[i], objectCount);
+
if (usesIntermediate(fmds[i])) {
- JumpInstruction elseIns = code.go2();
- // else if (!loaded.get(index))
- setTarget(code.aload().setThis(), jumps);
- jumps.add(elseIns);
- code.getfield().setField("loaded", BitSet.class);
- code.constant().setValue(i);
- code.invokevirtual().setMethod(BitSet.class, "get",
- boolean.class, new Class[]{ int.class });
- jumps.add(code.ifne());
+ // } else { ..
+ LabelNode lblEndElse = new LabelNode(); // new jump target for end else
+ instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEndElse));
+ instructions.add(lblEndIf); // actually this is now the begin of the else part
+ lblEndIf = new LabelNode(); //X TODO not sure!
+
+ // if (!loaded.get(index))
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "loaded", Type.getDescriptor(BitSet.class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(i));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "get",
+ Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.INT_TYPE)));
+ instructions.add(new JumpInsnNode(Opcodes.IFNE, lblEndElse));
// Object val = sm.getIntermediate(index);
// if (val != null)
// objects[objectCount] = val;
- code.aload().setParam(0);
- code.constant().setValue(i);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "getIntermediate", Object.class, new Class[]{ int.class });
- int local = code.getNextLocalsIndex();
- code.astore().setLocal(local);
- code.aload().setLocal(local);
- jumps.add(code.ifnull());
- code.aload().setThis();
- code.getfield().setField("objects", Object[].class);
- code.constant().setValue(objectCount);
- code.aload().setLocal(local);
- code.aastore();
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter
+ instructions.add(AsmHelper.getLoadConstantInsn(i));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(OpenJPAStateManager.class),
+ "getIntermediate",
+ Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT, Type.INT_TYPE)));
+ int localVarPos = AsmHelper.getLocalVarPos(store);
+ instructions.add(new VarInsnNode(Opcodes.ASTORE, localVarPos));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, localVarPos));
+ instructions.add(new JumpInsnNode(Opcodes.IFNULL, lblEndElse));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, localVarPos));
+ instructions.add(new InsnNode(Opcodes.AASTORE));
+
+ instructions.add(lblEndElse);
+ }
+
+ if (lblEndIf != null) {
+ instructions.add(lblEndIf);
}
+
if (replaceType(fmds[i]) >= JavaTypes.OBJECT)
objectCount++;
}
- setTarget(code.vreturn(), jumps);
- code.calculateMaxLocals();
- code.calculateMaxStack();
+
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
- private void addStore(BCClass bc, Code code, FieldMetaData fmd,
- int objectCount) {
+ private void addStore(ClassNode classNode, MethodNode meth, InsnList instructions, FieldMetaData fmd, int objectCount) {
int typeCode = replaceType(fmd);
int index = fmd.getIndex();
if (typeCode < JavaTypes.OBJECT) {
Class<?> type = forType(typeCode);
+
// field<i> = sm.fetch<Type>(index)
- code.aload().setThis();
- code.aload().setParam(0);
- code.constant().setValue(index);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "fetch" + StringUtil.capitalize(type.getName()), type,
- new Class[]{ int.class });
- code.putfield().setField(getFieldName(index), type);
- code.aload().setThis();
- code.getfield().setField("loaded", BitSet.class);
- code.constant().setValue(index);
- code.invokevirtual().setMethod(BitSet.class, "set", void.class,
- new Class[]{ int.class });
- } else {
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(OpenJPAStateManager.class),
+ "fetch" + StringUtil.capitalize(type.getName()),
+ Type.getMethodDescriptor(Type.getType(type), Type.INT_TYPE)));
+ instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, getFieldName(index), Type.getDescriptor(type)));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "loaded", Type.getDescriptor(BitSet.class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "set",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
+ }
+ else {
// Object val = toData(sm.getMetaData().getField(index),
// sm.fetchField(index, false), sm.getContext());
- int local = code.getNextLocalsIndex();
- code.aload().setThis();
- code.aload().setParam(0);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "getMetaData", ClassMetaData.class, null);
- code.constant().setValue(fmd.getIndex());
- code.invokevirtual().setMethod(ClassMetaData.class,
- "getField", FieldMetaData.class, new Class[]{ int.class });
- code.aload().setParam(0);
- code.constant().setValue(fmd.getIndex());
- code.constant().setValue(false);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "fetchField", Object.class, new Class[]
- { int.class, boolean.class });
- code.aload().setParam(0);
- code.invokeinterface().setMethod(OpenJPAStateManager.class,
- "getContext", StoreContext.class, null);
- code.invokevirtual().setMethod(bc.getName(), "toData",
- Object.class.getName(), toStrings(new Class []{
- FieldMetaData.class, Object.class, StoreContext.class }));
- code.astore().setLocal(local);
+ int localVarPos = AsmHelper.getLocalVarPos(meth);
+ 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(OpenJPAStateManager.class),
+ "getMetaData",
+ Type.getMethodDescriptor(Type.getType(ClassMetaData.class))));
+ instructions.add(AsmHelper.getLoadConstantInsn(fmd.getIndex()));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(ClassMetaData.class),
+ "getField",
+ Type.getMethodDescriptor(Type.getType(FieldMetaData.class), Type.INT_TYPE)));
+
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(AsmHelper.getLoadConstantInsn(fmd.getIndex()));
+ instructions.add(AsmHelper.getLoadConstantInsn(false));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(OpenJPAStateManager.class),
+ "fetchField",
+ Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT, Type.INT_TYPE, Type.BOOLEAN_TYPE)));
+
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(OpenJPAStateManager.class),
+ "getContext",
+ Type.getMethodDescriptor(Type.getType(StoreContext.class))));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "toData",
+ Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT,
+ Type.getType(FieldMetaData.class),
+ AsmHelper.TYPE_OBJECT,
+ Type.getType(StoreContext.class))));
+ instructions.add(new VarInsnNode(Opcodes.ASTORE, localVarPos));
// if (val == NULL) {
// val = null;
@@ -1097,43 +1153,59 @@ public class PCDataGenerator extends DynamicStorageGenerator {
// } else
// loaded.set(index);
// objects[objectCount] = val;
- code.aload().setLocal(local);
- code.getstatic().setField(AbstractPCData.class, "NULL",
- Object.class);
- JumpInstruction ifins = code.ifacmpne();
- code.constant().setNull();
- code.astore().setLocal(local);
- code.aload().setThis();
- code.getfield().setField("loaded", BitSet.class);
- code.constant().setValue(index);
- code.invokevirtual().setMethod(BitSet.class, "clear", void.class,
- new Class[]{ int.class });
- JumpInstruction go2 = code.go2();
- ifins.setTarget(code.aload().setThis());
- code.getfield().setField("loaded", BitSet.class);
- code.constant().setValue(index);
- code.invokevirtual().setMethod(BitSet.class, "set", void.class,
- new Class[]{ int.class });
- go2.setTarget(code.aload().setThis());
- code.getfield().setField("objects", Object[].class);
- code.constant().setValue(objectCount);
- code.aload().setLocal(local);
- code.aastore();
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, localVarPos));
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, Type.getInternalName(AbstractPCData.class),
+ "NULL", AsmHelper.TYPE_OBJECT.getDescriptor()));
+ LabelNode lblElse = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IF_ACMPNE, lblElse));
+ instructions.add(new InsnNode(Opcodes.ACONST_NULL));
+ instructions.add(new VarInsnNode(Opcodes.ASTORE, localVarPos));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "loaded", Type.getDescriptor(BitSet.class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "clear",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
+ LabelNode lblEndIf = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEndIf));
+
+ instructions.add(lblElse);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "loaded", Type.getDescriptor(BitSet.class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "set",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
+
+ instructions.add(lblEndIf);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "objects", Type.getDescriptor(Object[].class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(objectCount));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, localVarPos));
+ instructions.add(new InsnNode(Opcodes.AASTORE));
}
- if (!usesImplData(fmd))
+ if (!usesImplData(fmd)) {
return;
+ }
// storeImplData(sm, i, loaded.get(i);
- code.aload().setThis();
- code.aload().setParam(0);
- code.constant().setValue(index);
- code.aload().setThis();
- code.getfield().setField("loaded", BitSet.class);
- code.constant().setValue(index);
- code.invokevirtual().setMethod(BitSet.class, "get", boolean.class,
- new Class[]{ int.class });
- code.invokevirtual().setMethod("storeImplData", void.class,
- new Class[]{ OpenJPAStateManager.class, int.class, boolean.class });
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, "loaded", Type.getDescriptor(BitSet.class)));
+ instructions.add(AsmHelper.getLoadConstantInsn(index));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(BitSet.class),
+ "get",
+ Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.INT_TYPE)));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "storeImplData",
+ Type.getMethodDescriptor(Type.VOID_TYPE,
+ Type.getType(OpenJPAStateManager.class), Type.INT_TYPE, Type.BOOLEAN_TYPE)));
}
private void addNewEmbedded(BCClass bc) {