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, ); - 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, , 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, "", 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("", (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("") && 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 fields = managedType.getClassNode().fields; + List 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 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"; + } // = in.read (); - 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 (); - 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 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 (); - 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 fmd 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 true, then fmd is - * being loaded from an instance of the same class as the current execution - * context. If false, 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 fmd. 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;