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 62b14584f OPENJPA-2911 Externalizable in ASM
62b14584f is described below
commit 62b14584fbf6781164f5a01f8784cf79a0e493a6
Author: Mark Struberg <[email protected]>
AuthorDate: Thu Jul 13 11:06:21 2023 +0200
OPENJPA-2911 Externalizable in ASM
---
.../org/apache/openjpa/enhance/PCEnhancer.java | 770 +++++++++------------
.../org/apache/openjpa/util/asm/AsmHelper.java | 7 +-
2 files changed, 329 insertions(+), 448 deletions(-)
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
index 2ff67b469..377259dbe 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
@@ -604,6 +604,8 @@ public class PCEnhancer {
addAccessors(pc);
addAttachDetachCode();
+ AsmHelper.readIntoBCClass(pc, _pc);
+
addSerializationCode();
addCloningCode();
runAuxiliaryEnhancers();
@@ -1228,16 +1230,6 @@ public class PCEnhancer {
}
}
- @Deprecated
- private void addNotifyAccess(Code code, FieldMetaData fmd) {
- // PCHelper.accessingField(this, <absolute-index>);
- code.aload().setThis();
- code.constant().setValue(fmd.getIndex());
- code.invokestatic().setMethod(RedefinitionHelper.class,
- "accessingField", void.class,
- new Class[]{Object.class, int.class});
- }
-
/**
* This must be called after setting the value in the object.
*
@@ -1277,38 +1269,7 @@ public class PCEnhancer {
methodNode.instructions.insert(currentInsn, insns);
return insns.getLast();
}
- /**
- * This must be called after setting the value in the object.
- *
- * @param val the position in the local variable table where the
- * old value is stored
- * @param param the parameter position containing the new value, or
- * -1 if the new value is unavailable and should therefore be
looked
- * up.
- */
- @Deprecated
- private void addNotifyMutation(Code code, FieldMetaData fmd, int val, int
param)
- throws NoSuchMethodException {
- // PCHelper.settingField(this, <absolute-index>, old, new);
- code.aload().setThis();
- code.constant().setValue(fmd.getIndex());
- Class type = fmd.getDeclaredType();
- // we only have special signatures for primitives and Strings
- if (!type.isPrimitive() && type != String.class)
- type = Object.class;
- code.xload().setLocal(val).setType(type);
- if (param == -1) {
- loadManagedInstance(code, false);
- addGetManagedValueCode(code, fmd);
- }
- else {
- code.xload().setParam(param).setType(type);
- }
- code.invokestatic().setMethod(RedefinitionHelper.class, "settingField",
- void.class, new Class[]{
- Object.class, int.class, type, type
- });
- }
+
/**
* Return true if the given instruction accesses a field that is a backing
@@ -2525,62 +2486,6 @@ public class PCEnhancer {
instructions.add(new InsnNode(Opcodes.RETURN));
}
- /**
- * Adds the appropriate load method for the given type and local
- * index.
- */
- @Deprecated
- private void loadLocalValue(Code code, int locidx, int typeCode) {
- switch (typeCode) {
- case JavaTypes.CHAR:
- case JavaTypes.BYTE:
- case JavaTypes.SHORT:
- case JavaTypes.INT:
- code.iload().setLocal(locidx);
- break;
- case JavaTypes.DOUBLE:
- code.dload().setLocal(locidx);
- break;
- case JavaTypes.FLOAT:
- code.fload().setLocal(locidx);
- break;
- case JavaTypes.LONG:
- code.lload().setLocal(locidx);
- break;
- default:
- code.aload().setLocal(locidx);
- break;
- }
- }
-
- /**
- * Adds the appropriate store method for the given type and local
- * index.
- */
- @Deprecated
- private void storeLocalValue(Code code, int locidx, int typeCode) {
- switch (typeCode) {
- case JavaTypes.CHAR:
- case JavaTypes.BYTE:
- case JavaTypes.SHORT:
- case JavaTypes.INT:
- code.istore().setLocal(locidx);
- break;
- case JavaTypes.DOUBLE:
- code.dstore().setLocal(locidx);
- break;
- case JavaTypes.FLOAT:
- code.fstore().setLocal(locidx);
- break;
- case JavaTypes.LONG:
- code.lstore().setLocal(locidx);
- break;
- default:
- code.astore().setLocal(locidx);
- break;
- }
- }
-
/**
* Add code to extract the id of the given primary key relation field for
* setting into an objectid instance.
@@ -3406,19 +3311,6 @@ public class PCEnhancer {
return instructions;
}
- /**
- * Helper method to add the code necessary to throw the given
- * exception type, sans message.
- */
- @Deprecated
- private Instruction throwException(Code code, Class type) {
- Instruction ins = code.anew().setType(type);
- code.dup();
- code.invokespecial().setMethod(type, "<init>", void.class, null);
- code.athrow();
- return ins;
- }
-
/**
* Adds the PersistenceCapable interface to the class being
* enhanced, and adds a default constructor for use by OpenJPA
@@ -4636,8 +4528,6 @@ public class PCEnhancer {
addDetachedStateMethods(_meta.usesDetachedState() !=
Boolean.FALSE);
}
- AsmHelper.readIntoBCClass(pc, _pc);
-
// if we detach on serialize, we also need to implement the
// externalizable interface to write just the state for the fields
// being detached
@@ -4962,44 +4852,63 @@ public class PCEnhancer {
/**
* Implement the externalizable interface to detach on serialize.
*/
- private void addDetachExternalize(boolean parentDetachable,
- boolean detachedState)
+ private void addDetachExternalize(boolean parentDetachable, boolean
detachedState)
throws NoSuchMethodException {
// ensure that the declared default constructor is public
// for externalization
- BCMethod meth = _pc.getDeclaredMethod("<init>", (String[]) null);
- if (!meth.isPublic()) {
- if (_log.isWarnEnabled())
- _log.warn(_loc.get("enhance-defcons-extern",
- _meta.getDescribedType()));
- meth.makePublic();
+ final MethodNode ctNode = pc.getClassNode().methods.stream()
+ .filter(m -> m.name.equals("<init>") && m.desc.equals("()V"))
+ .findAny()
+ .get();
+
+
+ if ((ctNode.access & Opcodes.ACC_PUBLIC) == 0) {
+ if (_log.isWarnEnabled()) {
+ _log.warn(_loc.get("enhance-defcons-extern",
_meta.getDescribedType()));
+ }
+ ctNode.access = ctNode.access & ~Opcodes.ACC_PRIVATE &
~Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC;
}
+
// declare externalizable interface
- if (!Externalizable.class.isAssignableFrom(_meta.getDescribedType()))
- _pc.declareInterface(Externalizable.class);
+ if (!Externalizable.class.isAssignableFrom(_meta.getDescribedType())) {
+
pc.getClassNode().interfaces.add(Type.getInternalName(Externalizable.class));
+ }
// make sure the user doesn't already have custom externalization or
// serialization methods
- Class[] input = new Class[]{ObjectInputStream.class};
- Class[] output = new Class[]{ObjectOutputStream.class};
- if (_managedType.getDeclaredMethod("readObject", input) != null
- || _managedType.getDeclaredMethod("writeObject", output) !=
null)
+ String readObjectDesc = Type.getMethodDescriptor(Type.VOID_TYPE,
Type.getType(ObjectInputStream.class));
+ boolean hasReadObject = managedType.getClassNode().methods.stream()
+ .anyMatch(m -> m.name.equals("readObject") &&
m.desc.equals(readObjectDesc));
+
+ String writeObjectDesc = Type.getMethodDescriptor(Type.VOID_TYPE,
Type.getType(ObjectOutput.class));
+ boolean hasWriteObject = managedType.getClassNode().methods.stream()
+ .anyMatch(m -> m.name.equals("writeObject") &&
m.desc.equals(writeObjectDesc));
+
+ if (hasReadObject || hasWriteObject) {
throw new UserException(_loc.get("detach-custom-ser", _meta));
- input[0] = ObjectInput.class;
- output[0] = ObjectOutput.class;
- if (_managedType.getDeclaredMethod("readExternal", input) != null
- || _managedType.getDeclaredMethod("writeExternal", output) !=
null)
+ }
+
+ String readExternalDesc = Type.getMethodDescriptor(Type.VOID_TYPE,
Type.getType(ObjectInput.class));
+ boolean hasReadExternal = managedType.getClassNode().methods.stream()
+ .anyMatch(m -> m.name.equals("readExternal") &&
m.desc.equals(readExternalDesc));
+
+ String writeExternalDesc = Type.getMethodDescriptor(Type.VOID_TYPE,
Type.getType(ObjectInput.class));
+ boolean hasWriteExternal = managedType.getClassNode().methods.stream()
+ .anyMatch(m -> m.name.equals("writeExternal") &&
m.desc.equals(writeExternalDesc));
+
+ if (hasReadExternal || hasWriteExternal) {
throw new UserException(_loc.get("detach-custom-extern", _meta));
+ }
// create list of all unmanaged serializable fields
- BCField[] fields = _managedType.getDeclaredFields();
- Collection unmgd = new ArrayList(fields.length);
- for (BCField field : fields) {
- if (!field.isTransient() && !field.isStatic()
- && !field.isFinal()
- && !field.getName().startsWith(PRE)
- && _meta.getDeclaredField(field.getName()) == null)
+ final List<FieldNode> fields = managedType.getClassNode().fields;
+ List<FieldNode> unmgd = new ArrayList(fields.size());
+ for (FieldNode field : fields) {
+ if ((field.access & (Opcodes.ACC_TRANSIENT) | Opcodes.ACC_STATIC |
Opcodes.ACC_FINAL) == 0
+ && !field.name.startsWith(PRE)
+ && _meta.getDeclaredField(field.name) == null) {
unmgd.add(field);
+ }
}
addReadExternal(parentDetachable, detachedState);
@@ -5011,16 +4920,18 @@ public class PCEnhancer {
/**
* Add custom readExternal method.
*/
- @Deprecated
- private void addReadExternal(boolean parentDetachable,
- boolean detachedState)
+ private void addReadExternal(boolean parentDetachable, boolean
detachedState)
throws NoSuchMethodException {
- Class[] inargs = new Class[]{ObjectInput.class};
- BCMethod meth = _pc.declareMethod("readExternal", void.class, inargs);
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- exceps.addException(ClassNotFoundException.class);
- Code code = meth.getCode(true);
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+ MethodNode readExternalMeth = new MethodNode(Opcodes.ACC_PUBLIC,
+ "readExternal",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class),
+
Type.getInternalName(ClassNotFoundException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(readExternalMeth);
+ InsnList instructions = readExternalMeth.instructions;
// super.readExternal (in);
// not sure if this works: this is depending on the order of the
enhancement!
@@ -5028,146 +4939,171 @@ public class PCEnhancer {
// the Externalizable at this point!
Class<?> sup = _meta.getDescribedType().getSuperclass();
if (!parentDetachable && Externalizable.class.isAssignableFrom(sup)) {
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(sup, "readExternal",
- void.class, inargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+ Type.getInternalName(sup),
+ "readExternal",
+ methodDescriptor));
}
// readUnmanaged (in);
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokevirtual().setMethod(getType(_meta),
- PRE + "ReadUnmanaged", void.class,
inargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+
Type.getInternalName(getType(_meta)),
+ PRE + "ReadUnmanaged",
+ methodDescriptor));
if (detachedState) {
// pcSetDetachedState (in.readObject ());
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokeinterface().setMethod(ObjectInput.class, "readObject",
- Object.class, null);
- code.invokevirtual().setMethod(PRE + "SetDetachedState",
- void.class, new
Class[]{Object.class});
+ 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(ObjectInput.class),
+ "readObject",
+
Type.getMethodDescriptor(TYPE_OBJECT)));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ PRE + "SetDetachedState",
+
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
// pcReplaceStateManager ((StateManager) in.readObject ());
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokeinterface().setMethod(ObjectInput.class, "readObject",
- Object.class, null);
- code.checkcast().setType(StateManager.class);
- code.invokevirtual().setMethod(PRE + "ReplaceStateManager",
- void.class, new
Class[]{StateManager.class});
+ 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(ObjectInput.class),
+ "readObject",
+
Type.getMethodDescriptor(TYPE_OBJECT)));
+
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST,
Type.getInternalName(StateManager.class)));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ PRE + "ReplaceStateManager",
+
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(StateManager.class))));
}
addReadExternalFields();
// readExternalFields(in.readObject ());
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokevirtual().setMethod("readExternalFields",
- void.class, inargs);
-
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "readExternalFields",
+ methodDescriptor));
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
- @Deprecated
private void addReadExternalFields() throws NoSuchMethodException {
- Class<?>[] inargs = new Class[]{ObjectInput.class};
- BCMethod meth = _pc.declareMethod("readExternalFields", void.class,
inargs);
- meth.setAccessFlags(Constants.ACCESS_PROTECTED);
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- exceps.addException(ClassNotFoundException.class);
- Code code = meth.getCode(true);
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+ MethodNode readExternalMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+ "readExternalFields",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class),
+
Type.getInternalName(ClassNotFoundException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(readExternalMeth);
+ InsnList instructions = readExternalMeth.instructions;
Class<?> sup = _meta.getPCSuperclass();
if (sup != null) {
//add a call to super.readExternalFields()
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(sup, "readExternalFields",
void.class, inargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+ Type.getInternalName(sup),
+ "readExternalFields",
+ methodDescriptor));
}
// read managed fields
FieldMetaData[] fmds = _meta.getDeclaredFields();
for (FieldMetaData fmd : fmds) {
if (!fmd.isTransient()) {
- readExternal(code, fmd.getName(),
- fmd.getDeclaredType(), fmd);
+ readExternal(classNode, instructions, fmd.getName(),
Type.getType(fmd.getDeclaredType()), fmd);
}
}
-
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
/**
* Read unmanaged fields from the stream (pcReadUnmanaged).
*/
- @Deprecated
- private void addReadUnmanaged(Collection unmgd, boolean parentDetachable)
+ private void addReadUnmanaged(List<FieldNode> unmgd, boolean
parentDetachable)
throws NoSuchMethodException {
- Class[] inargs = new Class[]{ObjectInput.class};
- BCMethod meth = _pc.declareMethod(PRE + "ReadUnmanaged", void.class,
- inargs);
- meth.makeProtected();
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- exceps.addException(ClassNotFoundException.class);
- Code code = meth.getCode(true);
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectInput.class));
+ MethodNode readUnmanagedMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+ PRE + "ReadUnmanaged",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class),
+
Type.getInternalName(ClassNotFoundException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(readUnmanagedMeth);
+ InsnList instructions = readUnmanagedMeth.instructions;
// super.readUnmanaged (in);
if (parentDetachable) {
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(getType(_meta.
-
getPCSuperclassMetaData()), PRE + "ReadUnmanaged", void.class,
- inargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+
Type.getInternalName(getType(_meta.getPCSuperclassMetaData())),
+ PRE + "ReadUnmanaged",
+ methodDescriptor));
}
// read declared unmanaged serializable fields
- BCField field;
- for (Object o : unmgd) {
- field = (BCField) o;
- readExternal(code, field.getName(), field.getType(), null);
+ for (FieldNode field : unmgd) {
+ readExternal(classNode, instructions, field.name,
Type.getType(field.desc), null);
}
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
/**
* Helper method to read a field from an externalization input stream.
*/
- @Deprecated
- private void readExternal(Code code, String fieldName, Class type,
- FieldMetaData fmd)
+ private void readExternal(ClassNode classNode, InsnList instructions,
String fieldName, Type fieldType, FieldMetaData fmd)
throws NoSuchMethodException {
+
+ if (fieldType == null) {
+ fieldType = Type.getType(fmd.getDeclaredType());
+ }
+ String typeName = fieldType.getClassName();
+ boolean isPrimitive = fieldType.getSort() != Type.OBJECT &&
fieldType.getSort() != Type.ARRAY;
+
String methName;
- if (type.isPrimitive()) {
- methName = type.getName();
- methName = methName.substring(0, 1).toUpperCase(Locale.ENGLISH)
- + methName.substring(1);
+ if (isPrimitive) {
+ methName = typeName.substring(0, 1).toUpperCase(Locale.ENGLISH)
+ + typeName.substring(1);
methName = "read" + methName;
}
- else
+ else {
methName = "readObject";
+ }
// <field> = in.read<type> ();
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- Class ret = (type.isPrimitive()) ? type : Object.class;
- code.invokeinterface().setMethod(ObjectInput.class, methName,
- ret, null);
- if (!type.isPrimitive() && type != Object.class)
- code.checkcast().setType(type);
- if (fmd == null)
- putfield(code, null, fieldName, type);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ Type retType = isPrimitive ? fieldType : TYPE_OBJECT;
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+
Type.getInternalName(ObjectInput.class),
+ methName,
+
Type.getMethodDescriptor(retType)));
+
+ if (!isPrimitive &&
!fieldType.getClassName().equals(Object.class.getName())) {
+ instructions.add(new TypeInsnNode(Opcodes.CHECKCAST,
fieldType.getInternalName()));
+ }
+ if (fmd == null) {
+ Class<?> type = AsmHelper.getDescribedClass(pc.getClassLoader(),
fieldType.getDescriptor());
+ if (type == null) {
+ throw new RuntimeException("Cannot Load class " +
fieldType.getDescriptor());
+ }
+ putfield(classNode, instructions, null, fieldName, type);
+ }
else {
- addSetManagedValueCode(code, fmd);
+ addSetManagedValueCode(classNode, instructions, fmd);
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.DATE:
case JavaTypes.ARRAY:
@@ -5177,16 +5113,19 @@ public class PCEnhancer {
case JavaTypes.CALENDAR:
// if (sm != null)
// sm.proxyDetachedDeserialized (<index>);
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- IfInstruction ifins = code.ifnull();
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- code.constant().setValue(fmd.getIndex());
- code.invokeinterface().setMethod(SMTYPE,
-
"proxyDetachedDeserialized", void.class,
- new Class[]{int.class});
- ifins.setTarget(code.nop());
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); //
this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD,
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+
+ LabelNode lblEndIf = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFNULL,
lblEndIf));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); //
this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD,
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+
instructions.add(AsmHelper.getLoadConstantInsn(fmd.getIndex()));
+ instructions.add(new
MethodInsnNode(Opcodes.INVOKEINTERFACE,
+
Type.getInternalName(SMTYPE),
+
"proxyDetachedDeserialized",
+
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
+ instructions.add(lblEndIf);
}
}
}
@@ -5194,182 +5133,211 @@ public class PCEnhancer {
/**
* Add custom writeExternal method.
*/
- @Deprecated
- private void addWriteExternal(boolean parentDetachable,
- boolean detachedState)
+ private void addWriteExternal(boolean parentDetachable, boolean
detachedState)
throws NoSuchMethodException {
- Class[] outargs = new Class[]{ObjectOutput.class};
- BCMethod meth = _pc.declareMethod("writeExternal", void.class,
outargs);
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- Code code = meth.getCode(true);
+
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+ MethodNode writeExternalMeth = new MethodNode(Opcodes.ACC_PUBLIC,
+ "writeExternal",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(writeExternalMeth);
+ InsnList instructions = writeExternalMeth.instructions;
+
// super.writeExternal (out);
Class sup = getType(_meta).getSuperclass();
if (!parentDetachable && Externalizable.class.isAssignableFrom(sup)) {
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(sup, "writeExternal",
- void.class, outargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+ Type.getInternalName(sup),
+ "writeExternal",
+ methodDescriptor));
}
// writeUnmanaged (out);
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokevirtual().setMethod(getType(_meta),
- PRE + "WriteUnmanaged", void.class,
outargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+
Type.getInternalName(getType(_meta)),
+ PRE + "WriteUnmanaged",
+ methodDescriptor));
+
+ LabelNode go2 = null;
- JumpInstruction go2 = null;
if (detachedState) {
// if (sm != null)
// if (sm.writeDetached (out))
// return;
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- IfInstruction ifnull = code.ifnull();
- loadManagedInstance(code, false);
- code.getfield().setField(SM, SMTYPE);
- code.aload().setParam(0);
- code.invokeinterface().setMethod(SMTYPE, "writeDetached",
- boolean.class, outargs);
- go2 = code.ifeq();
- code.vreturn();
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD,
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+
+ LabelNode endIfNull = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFNULL, endIfNull));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new FieldInsnNode(Opcodes.GETFIELD,
classNode.name, SM, Type.getDescriptor(SMTYPE)));
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(SMTYPE),
+ "writeDetached",
+
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(ObjectOutput.class))));
+
+ go2 = new LabelNode();
+ instructions.add(new JumpInsnNode(Opcodes.IFEQ, go2));
+ instructions.add(new InsnNode(Opcodes.RETURN));
// else
// out.writeObject (pcGetDetachedState ());
- Class[] objargs = new Class[]{Object.class};
- ifnull.setTarget(code.aload().setParam(0));
- loadManagedInstance(code, false);
- code.invokevirtual().setMethod(PRE + "GetDetachedState",
- Object.class, null);
- code.invokeinterface().setMethod(ObjectOutput.class,
- "writeObject", void.class,
objargs);
- // out.writeObject (null) // StateManager
- code.aload().setParam(0);
- code.constant().setValue((Object) null);
- code.invokeinterface().setMethod(ObjectOutput.class,
- "writeObject", void.class,
objargs);
+ instructions.add(endIfNull);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ PRE + "GetDetachedState",
+
Type.getMethodDescriptor(TYPE_OBJECT)));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+
Type.getInternalName(ObjectOutput.class),
+ "writeObject",
+
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
+
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(AsmHelper.getLoadConstantInsn(null));
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+
Type.getInternalName(ObjectOutput.class),
+ "writeObject",
+
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT)));
+ }
+ if (go2 != null) {
+ instructions.add(go2);
}
- if (go2 != null)
- go2.setTarget(code.nop());
addWriteExternalFields();
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokevirtual().setMethod("writeExternalFields",
- void.class, outargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
+ classNode.name,
+ "writeExternalFields",
+ methodDescriptor));
// return
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
- @Deprecated
- private void addWriteExternalFields()
- throws NoSuchMethodException {
- Class<?>[] outargs = new Class[]{ObjectOutput.class};
- BCMethod meth = _pc.declareMethod("writeExternalFields", void.class,
outargs);
- meth.setAccessFlags(Constants.ACCESS_PROTECTED);
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- Code code = meth.getCode(true);
+ private void addWriteExternalFields() throws NoSuchMethodException {
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+ MethodNode writeExternalFieldsMeth = new
MethodNode(Opcodes.ACC_PROTECTED,
+ "writeExternalFields",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(writeExternalFieldsMeth);
+ InsnList instructions = writeExternalFieldsMeth.instructions;
Class<?> sup = _meta.getPCSuperclass();
if (sup != null) {
- // add a call to super.readExternalFields()
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(sup, "writeExternalFields",
void.class, outargs);
+ // add a call to super.writeExternalFields()
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+ Type.getInternalName(sup),
+ "writeExternalFields",
+ methodDescriptor));
}
FieldMetaData[] fmds = _meta.getDeclaredFields();
for (FieldMetaData fmd : fmds) {
if (!fmd.isTransient()) {
- writeExternal(code, fmd.getName(),
- fmd.getDeclaredType(), fmd);
+ writeExternal(classNode, instructions, fmd.getName(),
+ Type.getType(fmd.getDeclaredType()), fmd);
}
}
// return
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
/**
* Write unmanaged fields to the stream (pcWriteUnmanaged).
*/
- @Deprecated
- private void addWriteUnmanaged(Collection unmgd, boolean parentDetachable)
+ private void addWriteUnmanaged(List<FieldNode> unmgd, boolean
parentDetachable)
throws NoSuchMethodException {
- Class[] outargs = new Class[]{ObjectOutput.class};
- BCMethod meth = _pc.declareMethod(PRE + "WriteUnmanaged", void.class,
- outargs);
- meth.makeProtected();
- Exceptions exceps = meth.getExceptions(true);
- exceps.addException(IOException.class);
- Code code = meth.getCode(true);
+ final String methodDescriptor =
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(ObjectOutput.class));
+ MethodNode writeUnmanagedMeth = new MethodNode(Opcodes.ACC_PROTECTED,
+ PRE + "WriteUnmanaged",
+ methodDescriptor,
+ null,
+ new String[]
{Type.getInternalName(IOException.class)});
+ final ClassNode classNode = pc.getClassNode();
+ classNode.methods.add(writeUnmanagedMeth);
+ InsnList instructions = writeUnmanagedMeth.instructions;
// super.writeUnmanaged (out);
if (parentDetachable) {
- loadManagedInstance(code, false);
- code.aload().setParam(0);
- code.invokespecial().setMethod(getType(_meta.
-
getPCSuperclassMetaData()), PRE + "WriteUnmanaged", void.class,
- outargs);
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
+
Type.getInternalName(getType(_meta.getPCSuperclassMetaData())),
+ PRE + "WriteUnmanaged",
+ methodDescriptor));
}
// write declared unmanaged serializable fields
- BCField field;
- for (Object o : unmgd) {
- field = (BCField) o;
- writeExternal(code, field.getName(), field.getType(), null);
+ for (FieldNode field : unmgd) {
+ writeExternal(classNode, instructions, field.name,
Type.getType(field.desc), null);
}
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
+ instructions.add(new InsnNode(Opcodes.RETURN));
}
/**
* Helper method to write a field to an externalization output stream.
*/
- @Deprecated
- private void writeExternal(Code code, String fieldName, Class type,
- FieldMetaData fmd)
+ private void writeExternal(ClassNode classNode, InsnList instructions,
String fieldName, Type fieldType, FieldMetaData fmd)
throws NoSuchMethodException {
+ String typeName = fieldType.getClassName();
+ boolean isPrimitive = fieldType.getSort() != Type.OBJECT &&
fieldType.getSort() != Type.ARRAY;
+
String methName;
- if (type.isPrimitive()) {
- methName = type.getName();
- methName = methName.substring(0, 1).toUpperCase(Locale.ENGLISH)
- + methName.substring(1);
+ if (isPrimitive) {
+ methName = typeName.substring(0, 1).toUpperCase(Locale.ENGLISH)
+ + typeName.substring(1);
methName = "write" + methName;
}
- else
+ else {
methName = "writeObject";
+ }
// out.write<type> (<field>);
- code.aload().setParam(0);
- loadManagedInstance(code, false);
- if (fmd == null)
- getfield(code, null, fieldName);
- else
- addGetManagedValueCode(code, fmd);
- Class[] args = new Class[]{type};
- if (type == byte.class || type == char.class || type == short.class)
- args[0] = int.class;
- else if (!type.isPrimitive())
- args[0] = Object.class;
- code.invokeinterface().setMethod(ObjectOutput.class, methName,
- void.class, args);
- }
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param
+ instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
- @Deprecated
- private void addGetManagedValueCode(Code code, FieldMetaData fmd)
- throws NoSuchMethodException {
- addGetManagedValueCode(code, fmd, true);
+ if (fmd == null) {
+ Class<?> type = AsmHelper.getDescribedClass(pc.getClassLoader(),
fieldType.getDescriptor());
+ getfield(classNode, instructions, null, fieldName, type);
+ }
+ else {
+ addGetManagedValueCode(classNode, instructions, fmd, true);
+ }
+
+ String mdesc;
+ if (fieldType.getSort() == Type.BYTE || fieldType.getSort() ==
Type.CHAR || fieldType.getSort() == Type.SHORT) {
+ mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+ }
+ else if (!isPrimitive) {
+ mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
+ }
+ else {
+ mdesc = Type.getMethodDescriptor(Type.VOID_TYPE, fieldType);
+ }
+ instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
+
Type.getInternalName(ObjectOutput.class),
+ methName,
+ mdesc));
}
@@ -5420,50 +5388,6 @@ public class PCEnhancer {
}
}
- /**
- * Load the field value specified by <code>fmd</code> onto the stack.
- * Before this method is called, the object that the data should be loaded
- * from will be on the top of the stack.
- *
- * @param fromSameClass if <code>true</code>, then <code>fmd</code> is
- * being loaded from an instance of the same class as
the current execution
- * context. If <code>false</code>, then the instance
on the top of the stack
- * might be a superclass of the current execution
context's 'this' instance.
- */
- @Deprecated
- private void addGetManagedValueCode(Code code, FieldMetaData fmd,
- boolean fromSameClass)
- throws NoSuchMethodException {
- // if redefining, then we must always reflect (or access the field
- // directly if accessible), since the redefined methods will always
- // trigger method calls to StateManager, even from internal direct-
- // access usage. We could work around this by not redefining, and
- // just do a subclass approach instead. But this is not a good option,
- // since it would sacrifice lazy loading and efficient dirty tracking.
-
- if (getRedefine() || isFieldAccess(fmd)) {
- getfield(code, null, fmd.getName());
- }
- else if (getCreateSubclass()) {
- // property access, and we're not redefining. If we're operating
- // on an instance that is definitely the same type as 'this', then
- // call superclass method to bypass tracking. Otherwise, reflect
- // to both bypass tracking and avoid class verification errors.
- if (fromSameClass) {
- Method meth = (Method) fmd.getBackingMember();
- code.invokespecial().setMethod(meth);
- }
- else {
- getfield(code, null, fmd.getName());
- }
- }
- else {
- // regular enhancement + property access
- Method meth = (Method) fmd.getBackingMember();
- code.invokevirtual().setMethod(PRE + meth.getName(),
- meth.getReturnType(),
meth.getParameterTypes());
- }
- }
/**
* Store the given value into the field value specified
@@ -5540,36 +5464,6 @@ public class PCEnhancer {
}
}
- /**
- * Store the value at the top of the stack into the field value specified
- * by <code>fmd</code>. Before this method is called, the data to load will
- * be on the top of the stack and the object that the data should be loaded
- * into will be second in the stack.
- */
- @Deprecated
- private void addSetManagedValueCode(Code code, FieldMetaData fmd)
- throws NoSuchMethodException {
- // if redefining, then we must always reflect (or access the field
- // directly if accessible), since the redefined methods will always
- // trigger method calls to StateManager, even from internal direct-
- // access usage. We could work around this by not redefining, and
- // just do a subclass approach instead. But this is not a good option,
- // since it would sacrifice lazy loading and efficient dirty tracking.
-
- if (getRedefine() || isFieldAccess(fmd)) {
- putfield(code, null, fmd.getName(), fmd.getDeclaredType());
- } else if (getCreateSubclass()) {
- // property access, and we're not redefining. invoke the
- // superclass method to bypass tracking.
- code.invokespecial().setMethod(_managedType.getType(),
- getSetterName(fmd), void.class,
- new Class[] { fmd.getDeclaredType() });
- } else {
- // regular enhancement + property access
- code.invokevirtual().setMethod(PRE + getSetterName(fmd),
- void.class, new Class[] { fmd.getDeclaredType() });
- }
- }
/**
* Add the {@link Instruction}s to load the instance to modify onto the
@@ -5762,22 +5656,6 @@ public class PCEnhancer {
return meta.getDescribedType();
}
- /**
- * Move code-related attributes from one method to another.
- */
- @Deprecated
- private static void transferCodeAttributes(BCMethod from, BCMethod to) {
- Code code = from.getCode(false);
- if (code != null) {
- to.addAttribute(code);
- from.removeCode();
- }
-
- Exceptions exceps = from.getExceptions(false);
- if (exceps != null)
- to.addAttribute(exceps);
- }
-
/**
* Usage: java org.apache.openjpa.enhance.PCEnhancer [option]*
* <class name | .java file | .class file | .jdo file>+
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
index b92da8438..6c7f8c919 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
@@ -610,15 +610,18 @@ public final class AsmHelper {
return long.class;
case 'D':
return double.class;
+ case 'L':
+ if (typeDesc.charAt(typeDesc.length()-1) == ';')
+ return getClass(classLoader, typeDesc.substring(1,
typeDesc.length()-1));
default:
// some kind of class
return getClass(classLoader, typeDesc);
}
}
- private static Class<?> getClass(ClassLoader classLoader, String typeName)
{
+ public static Class<?> getClass(ClassLoader classLoader, String
internalTypeName) {
try {
- return Class.forName(typeName.replace("/", "."), false,
classLoader);
+ return Class.forName(internalTypeName.replace("/", "."), false,
classLoader);
}
catch (NoClassDefFoundError | ClassNotFoundException e) {
return null;