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