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 <[email protected]>
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);
}
}