OPENJPA-2911 few more internal methods in ASM

* pcGetVersion
* translateFromStateManagerMethod
This commit is contained in:
Mark Struberg 2023-06-21 15:39:00 +02:00
parent 94d1874019
commit 77d8a8e05b
2 changed files with 126 additions and 141 deletions

View File

@ -603,7 +603,7 @@ public class PCEnhancer {
//X addStaticInitializer(pc);
addStaticInitializer(); // removeme
addPCMethods(pc);
addPCMethods();
addAccessors();
addAttachDetachCode();
@ -1353,28 +1353,31 @@ public class PCEnhancer {
* <code>pcFetchObjectId</code>, etc are defined only in the
* least-derived PersistenceCapable type.
*/
private void addPCMethods(ClassNodeTracker classNodeTracker) throws NoSuchMethodException {
addClearFieldsMethod(classNodeTracker.getClassNode());
private void addPCMethods() throws NoSuchMethodException {
addClearFieldsMethod(pc.getClassNode());
addNewInstanceMethod(classNodeTracker.getClassNode(), true);
addNewInstanceMethod(classNodeTracker.getClassNode(), false);
addNewInstanceMethod(pc.getClassNode(), true);
addNewInstanceMethod(pc.getClassNode(), false);
addManagedFieldCountMethod(classNodeTracker.getClassNode());
addReplaceFieldsMethods(classNodeTracker.getClassNode());
addProvideFieldsMethods(classNodeTracker.getClassNode());
addManagedFieldCountMethod(pc.getClassNode());
addReplaceFieldsMethods(pc.getClassNode());
addProvideFieldsMethods(pc.getClassNode());
addCopyFieldsMethod(classNodeTracker.getClassNode());
addCopyFieldsMethod(pc.getClassNode());
AsmHelper.readIntoBCClass(classNodeTracker, _pc);
if (_meta.getPCSuperclass() == null || getCreateSubclass()) {
addStockMethods();
addGetVersionMethod();
AsmHelper.readIntoBCClass(pc, _pc);
addReplaceStateManagerMethod();
if (_meta.getIdentityType() != ClassMetaData.ID_APPLICATION)
addNoOpApplicationIdentityMethods();
}
else { //X TODO remove whole else
AsmHelper.readIntoBCClass(pc, _pc);
}
// add the app id methods to each subclass rather
// than just the superclass, since it is possible to have
@ -1932,172 +1935,169 @@ public class PCEnhancer {
* like {@link PersistenceCapable#pcFetchObjectId}
* and {@link PersistenceCapable#pcIsTransactional}.
*/
private void addStockMethods()
throws NoSuchMethodException {
try {
// pcGetGenericContext
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "get" + CONTEXTNAME, (Class[]) null)), false);
private void addStockMethods() throws NoSuchMethodException {
// pcGetGenericContext
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("get" + CONTEXTNAME), false);
// pcFetchObjectId
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "fetchObjectId", (Class[]) null)), false);
// pcFetchObjectId
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("fetchObjectId"), false);
// pcIsDeleted
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "isDeleted", (Class[]) null)), false);
// pcIsDeleted
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("isDeleted"), false);
// pcIsDirty
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "isDirty", (Class[]) null)), true);
// pcIsDirty
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("isDirty"), true);
// pcIsNew
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "isNew", (Class[]) null)), false);
// pcIsNew
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("isNew"), false);
// pcIsPersistent
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "isPersistent", (Class[]) null)), false);
// pcIsPersistent
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("isPersistent"), false);
// pcIsTransactional
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "isTransactional", (Class[]) null)), false);
// pcIsTransactional
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("isTransactional"), false);
// pcSerializing
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "serializing", (Class[]) null)), false);
// pcSerializing
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("serializing"), false);
// pcDirty
translateFromStateManagerMethod(
AccessController.doPrivileged(
J2DoPrivHelper.getDeclaredMethodAction(
SMTYPE, "dirty", new Class[]{String.class})), false);
// pcDirty
translateFromStateManagerMethod(SMTYPE.getDeclaredMethod("dirty", String.class), false);
// pcGetStateManager
BCMethod meth = _pc.declareMethod(PRE + "GetStateManager",
StateManager.class, null);
Code code = meth.getCode(true);
loadManagedInstance(code, false);
code.getfield().setField(SM, StateManager.class);
code.areturn();
code.calculateMaxStack();
code.calculateMaxLocals();
}
catch (PrivilegedActionException pae) {
throw (NoSuchMethodException) pae.getException();
}
// pcGetStateManager
MethodNode getSmMeth = new MethodNode(Opcodes.ACC_PUBLIC,
PRE + "GetStateManager",
Type.getMethodDescriptor(Type.getType(SMTYPE)),
null, null);
pc.getClassNode().methods.add(getSmMeth);
InsnList instructions = getSmMeth.instructions;
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, pc.getClassNode().name, SM, Type.getDescriptor(SMTYPE)));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
/**
* Helper method to add a stock method to the bytecode. Each
* stock method simply delegates to a corresponding StateManager method.
* Given the StateManager method, then, this function translates it into
* the wrapper method that should be added to the bytecode.
*/
private void translateFromStateManagerMethod(Method m,
boolean isDirtyCheckMethod) {
private void translateFromStateManagerMethod(Method m, boolean isDirtyCheckMethod) {
// form the name of the method by prepending 'pc' to the sm method
String name = PRE + StringUtil.capitalize(m.getName());
Class[] params = m.getParameterTypes();
Type[] paramTypes = Arrays.stream(params)
.map(p -> Type.getType(p))
.toArray(Type[]::new);
Class returnType = m.getReturnType();
final ClassNode classNode = pc.getClassNode();
// add the method to the pc
BCMethod method = _pc.declareMethod(name, returnType, params);
Code code = method.getCode(true);
MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC,
name,
Type.getMethodDescriptor(Type.getType(returnType), paramTypes),
null, null);
InsnList instructions = methodNode.instructions;
classNode.methods.add(methodNode);
// if (pcStateManager == null) return <default>;
loadManagedInstance(code, false);
code.getfield().setField(SM, SMTYPE);
JumpInstruction ifins = code.ifnonnull();
if (returnType.equals(boolean.class))
code.constant().setValue(false);
else if (!returnType.equals(void.class))
code.constant().setNull();
code.xreturn().setType(returnType);
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
LabelNode lblAfterIf = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblAfterIf));
if (returnType.equals(boolean.class)) {
instructions.add(new InsnNode(Opcodes.ICONST_0)); // false
}
else if (!returnType.equals(void.class)) {
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
}
instructions.add(new InsnNode(AsmHelper.getReturnInsn(returnType)));
instructions.add(lblAfterIf);
// load the StateManager onto the stack
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
// if this is the dirty-check method and we're subclassing but not
// redefining, hook into PCHelper to do the dirty check
if (isDirtyCheckMethod && !getRedefine()) {
// RedefinitionHelper.dirtyCheck(sm);
ifins.setTarget(loadManagedInstance(code, false));
code.getfield().setField(SM, SMTYPE);
code.dup(); // for the return statement below
code.invokestatic().setMethod(RedefinitionHelper.class,
"dirtyCheck", void.class, new Class[]{SMTYPE});
}
else {
ifins.setTarget(loadManagedInstance(code, false));
code.getfield().setField(SM, SMTYPE);
instructions.add(new InsnNode(Opcodes.DUP)); // duplicate the StateManager for the return statement below
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
Type.getInternalName(RedefinitionHelper.class),
"dirtyCheck",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(SMTYPE))));
}
// return pcStateManager.<method> (<args>);
// managed instance loaded above in if-else block
for (int i = 0; i < params.length; i++)
code.xload().setParam(i);
code.invokeinterface().setMethod(m);
code.xreturn().setType(returnType);
for (int i = 0; i < params.length; i++) {
instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(params[i]), i+1));
}
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(SMTYPE),
m.getName(),
Type.getMethodDescriptor(m)));
code.calculateMaxStack();
code.calculateMaxLocals();
instructions.add(new InsnNode(AsmHelper.getReturnInsn(returnType)));
}
/**
* Adds the {@link PersistenceCapable#pcGetVersion} method to the bytecode.
*/
private void addGetVersionMethod()
throws NoSuchMethodException {
BCMethod method = _pc.declareMethod(PRE + "GetVersion", Object.class,
null);
Code code = method.getCode(true);
private void addGetVersionMethod() throws NoSuchMethodException {
final ClassNode classNode = pc.getClassNode();
MethodNode getVersionMeth = new MethodNode(Opcodes.ACC_PUBLIC,
PRE + "GetVersion",
Type.getMethodDescriptor(TYPE_OBJECT),
null, null);
classNode.methods.add(getVersionMeth);
InsnList instructions = getVersionMeth.instructions;
// if (pcStateManager == null)
loadManagedInstance(code, false);
code.getfield().setField(SM, SMTYPE);
JumpInstruction ifins = code.ifnonnull();
FieldMetaData versionField = _meta.getVersionField();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
LabelNode lblAfterIf = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblAfterIf));
if (versionField == null)
code.constant().setNull(); // return null;
FieldMetaData versionField = _meta.getVersionField();
if (versionField == null) {
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
}
else {
// return <versionField>;
Class wrapper = toPrimitiveWrapper(versionField);
if (wrapper != versionField.getDeclaredType()) {
code.anew().setType(wrapper);
code.dup();
instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(wrapper)));
instructions.add(new InsnNode(Opcodes.DUP));
}
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
addGetManagedValueCode(classNode, instructions, versionField, true);
if (wrapper != versionField.getDeclaredType()) {
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
Type.getInternalName(wrapper),
"<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(versionField.getDeclaredType()))));
}
loadManagedInstance(code, false);
addGetManagedValueCode(code, versionField);
if (wrapper != versionField.getDeclaredType())
code.invokespecial().setMethod(wrapper, "<init>", void.class,
new Class[]{versionField.getDeclaredType()});
}
code.areturn();
instructions.add(new InsnNode(Opcodes.ARETURN));
instructions.add(lblAfterIf);
// return pcStateManager.getVersion ();
ifins.setTarget(loadManagedInstance(code, false));
code.getfield().setField(SM, SMTYPE);
code.invokeinterface().setMethod(SMTYPE, "getVersion", Object.class,
null);
code.areturn();
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
code.calculateMaxStack();
code.calculateMaxLocals();
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
Type.getInternalName(SMTYPE),
"getVersion",
Type.getMethodDescriptor(TYPE_OBJECT)));
instructions.add(new InsnNode(Opcodes.ARETURN));
}
/**
@ -3388,7 +3388,8 @@ public class PCEnhancer {
}
else {
// pcInheritedFieldCount = <superClass>.pcGetManagedFieldCount()
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, classNode.superName,
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
classNode.superName,
PRE + "GetManagedFieldCount",
Type.getMethodDescriptor(Type.INT_TYPE)));
instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, INHERIT, Type.INT_TYPE.getDescriptor()));
@ -3436,7 +3437,6 @@ public class PCEnhancer {
}
instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, PRE + "FieldFlags", Type.getDescriptor(byte[].class)));
/*
// PCRegistry.register (cls,
// pcFieldNames, pcFieldTypes, pcFieldFlags,
// pcPCSuperclass, alias, new XXX ());
@ -3474,8 +3474,6 @@ public class PCEnhancer {
Type.getType(Class.class), Type.getType(String.class),
Type.getType(PersistenceCapable.class))));
*/
// now add those instructions to the <clinit> method
MethodNode clinit = getOrCreateClassInitMethod(classNode);
final AbstractInsnNode retInsn = clinit.instructions.getLast();

View File

@ -69,19 +69,6 @@ public class SimpleEntity implements Serializable {
public static final String NAMED_QUERY_WITH_POSITIONAL_PARAMS = "SelectWithPositionalParameter";
public static final String NAMED_QUERY_WITH_NAMED_PARAMS = "SelectWithNamedParameter";
public static Integer dummy;
static {
dummy = -32766;
dummy = -32767;
dummy = -32768;
dummy = -32769;
dummy = 32765;
dummy = 32766;
dummy = 32767;
dummy = 32768;
}
@Id
@GeneratedValue