OPENJPA-2911 migrate addNewInstance to ASM

This commit is contained in:
Mark Struberg 2023-06-06 17:34:28 +02:00
parent 4c7c81d249
commit 972b5d0e62
1 changed files with 69 additions and 38 deletions

View File

@ -107,9 +107,12 @@ import org.apache.xbean.asm9.tree.FieldInsnNode;
import org.apache.xbean.asm9.tree.FieldNode; import org.apache.xbean.asm9.tree.FieldNode;
import org.apache.xbean.asm9.tree.InsnList; import org.apache.xbean.asm9.tree.InsnList;
import org.apache.xbean.asm9.tree.InsnNode; 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.LdcInsnNode; import org.apache.xbean.asm9.tree.LdcInsnNode;
import org.apache.xbean.asm9.tree.MethodInsnNode; import org.apache.xbean.asm9.tree.MethodInsnNode;
import org.apache.xbean.asm9.tree.MethodNode; import org.apache.xbean.asm9.tree.MethodNode;
import org.apache.xbean.asm9.tree.TypeInsnNode;
import org.apache.xbean.asm9.tree.VarInsnNode; import org.apache.xbean.asm9.tree.VarInsnNode;
import serp.bytecode.BCClass; import serp.bytecode.BCClass;
@ -1337,12 +1340,12 @@ public class PCEnhancer {
* least-derived PersistenceCapable type. * least-derived PersistenceCapable type.
*/ */
private void addPCMethods(ClassNodeTracker classNodeTracker) throws NoSuchMethodException { private void addPCMethods(ClassNodeTracker classNodeTracker) throws NoSuchMethodException {
//X addClearFieldsMethod();
addClearFieldsMethod(classNodeTracker.getClassNode()); addClearFieldsMethod(classNodeTracker.getClassNode());
addNewInstanceMethod(classNodeTracker.getClassNode(), true);
addNewInstanceMethod(classNodeTracker.getClassNode(), false);
AsmHelper.readIntoBCClass(classNodeTracker, _pc); AsmHelper.readIntoBCClass(classNodeTracker, _pc);
addNewInstanceMethod(true);
addNewInstanceMethod(false);
addManagedFieldCountMethod(); addManagedFieldCountMethod();
addReplaceFieldsMethods(); addReplaceFieldsMethods();
addProvideFieldsMethods(); addProvideFieldsMethods();
@ -1384,7 +1387,7 @@ public class PCEnhancer {
addGetIDOwningClass(); addGetIDOwningClass();
} }
} }
/** /**
* Add a method to clear all persistent fields; we'll call this from * Add a method to clear all persistent fields; we'll call this from
* the new instance method to ensure that unloaded fields have * the new instance method to ensure that unloaded fields have
@ -1448,58 +1451,68 @@ public class PCEnhancer {
* @param oid set to true to mimic the method version that takes * @param oid set to true to mimic the method version that takes
* an oid value as well as a state manager * an oid value as well as a state manager
*/ */
private void addNewInstanceMethod(boolean oid) { private void addNewInstanceMethod(ClassNode classNode, boolean oid) {
// public PersistenceCapable pcNewInstance (...) // public PersistenceCapable pcNewInstance (...)
Class[] args = String desc = oid
(oid) ? new Class[]{ SMTYPE, Object.class, boolean.class } ? Type.getMethodDescriptor(Type.getType(PCTYPE), Type.getType(SMTYPE), Type.getType(Object.class), Type.BOOLEAN_TYPE)
: new Class[]{ SMTYPE, boolean.class }; : Type.getMethodDescriptor(Type.getType(PCTYPE), Type.getType(SMTYPE), Type.BOOLEAN_TYPE);
BCMethod method = _pc.declareMethod(PRE + "NewInstance", PCTYPE, args); MethodNode newInstance = new MethodNode(Opcodes.ACC_PUBLIC,
Code code = method.getCode(true); PRE + "NewInstance",
desc,
null, null);
classNode.methods.add(newInstance);
final InsnList instructions = newInstance.instructions;
// if the type is abstract, throw a UserException
if (_pc.isAbstract()) { if (_pc.isAbstract()) {
throwException(code, USEREXCEP); instructions.add(throwException(USEREXCEP));
code.calculateMaxStack();
code.calculateMaxLocals();
return; return;
} }
// XXX pc = new XXX (); // XXX pc = new XXX ();
code.anew().setType(_pc); instructions.add(new TypeInsnNode(Opcodes.NEW, classNode.name));
code.dup(); instructions.add(new InsnNode(Opcodes.DUP));
code.invokespecial().setMethod("<init>", void.class, null); instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
int inst = code.getNextLocalsIndex(); classNode.name,
code.astore().setLocal(inst); "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE)));
int newPcVarPos = (oid) ? 4 : 3; // number of params +1
instructions.add(new VarInsnNode(Opcodes.ASTORE, newPcVarPos));
// if (clear) // if (clear)
// pc.pcClearFields (); // pc.pcClearFields ();
code.iload().setParam((oid) ? 2 : 1); instructions.add(new VarInsnNode(Opcodes.ILOAD, (oid) ? 3 : 2));
JumpInstruction noclear = code.ifeq(); LabelNode labelAfterClearFields = new LabelNode();
code.aload().setLocal(inst); instructions.add(new JumpInsnNode(Opcodes.IFEQ, labelAfterClearFields));
code.invokevirtual().setMethod(PRE + "ClearFields", void.class, null);
// inside the if
instructions.add(new VarInsnNode(Opcodes.ALOAD, newPcVarPos));
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
classNode.name,
PRE + "ClearFields",
Type.getMethodDescriptor(Type.VOID_TYPE)));
instructions.add(labelAfterClearFields);
// pc.pcStateManager = sm; // pc.pcStateManager = sm;
noclear.setTarget(code.aload().setLocal(inst)); instructions.add(new VarInsnNode(Opcodes.ALOAD, newPcVarPos));
code.aload().setParam(0); instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // the 1st method param
code.putfield().setField(SM, SMTYPE); instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
// copy key fields from oid // copy key fields from oid
if (oid) { if (oid) {
code.aload().setLocal(inst); instructions.add(new VarInsnNode(Opcodes.ALOAD, newPcVarPos));
code.aload().setParam(1); instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); // the 2nd method param, Object
code.invokevirtual().setMethod(PRE + "CopyKeyFieldsFromObjectId", instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
void.class, new Class[]{ Object.class }); classNode.name,
PRE + "CopyKeyFieldsFromObjectId",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class))));
} }
// return pc; instructions.add(new VarInsnNode(Opcodes.ALOAD, newPcVarPos));
code.aload().setLocal(inst); instructions.add(new InsnNode(Opcodes.ARETURN));
code.areturn();
code.calculateMaxStack();
code.calculateMaxLocals();
} }
/** /**
* Adds the <code>protected static int pcGetManagedFieldCount ()</code> * Adds the <code>protected static int pcGetManagedFieldCount ()</code>
* method to the bytecode, returning the inherited field count added * method to the bytecode, returning the inherited field count added
@ -3061,6 +3074,24 @@ public class PCEnhancer {
} }
} }
/**
* Helper method to add the code necessary to throw the given
* exception type, sans message.
*/
private InsnList throwException(Class type) {
InsnList instructions = new InsnList();
instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(type)));
instructions.add(new InsnNode(Opcodes.DUP));
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
Type.getInternalName(type),
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE)));
instructions.add(new InsnNode(Opcodes.ATHROW));
return instructions;
}
/** /**
* Helper method to add the code necessary to throw the given * Helper method to add the code necessary to throw the given
* exception type, sans message. * exception type, sans message.