private void addInitializationLogicToConstructors() { if (!classMetadata.hasManagedFieldsWithFieldGranularity()) { return; } for (MethodNode methodNode : (List<MethodNode>) classNode.methods) { MethodMetadata methodMetadata = classMetadata.getMethodMetadata(methodNode.name, methodNode.desc); if (methodMetadata.isTransactional() && methodMetadata.isConstructor()) { int firstAfterSuper = firstIndexAfterSuper(methodNode, classNode.superName); if (firstAfterSuper >= 0) { InsnList extraInstructions = new InsnList(); for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) { FieldMetadata fieldMetadata = classMetadata.getFieldMetadata(fieldNode.name); if (fieldMetadata.hasFieldGranularity()) { extraInstructions.add(new VarInsnNode(ALOAD, 0)); String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); extraInstructions.add(new TypeInsnNode(NEW, referenceName)); extraInstructions.add(new InsnNode(DUP)); extraInstructions.add( new MethodInsnNode(INVOKESPECIAL, referenceName, "<init>", "()V")); extraInstructions.add( new FieldInsnNode(PUTFIELD, classNode.name, fieldNode.name, referenceDesc)); } AbstractInsnNode first = methodNode.instructions.get(firstAfterSuper); methodNode.instructions.insert(first, extraInstructions); } } } } }
private void fixFieldAccessInMethods() { List<MethodNode> methods = new LinkedList<MethodNode>(); for (MethodNode methodNode : (List<MethodNode>) classNode.methods) { MethodMetadata methodMetadata = classMetadata.getMethodMetadata(methodNode.name, methodNode.desc); if (methodMetadata.isTransactional()) { methodNode = fixMethod(methodNode); } methods.add(methodNode); } classNode.methods = methods; }
private void fixFields() { List<FieldNode> fields = new LinkedList<FieldNode>(); for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) { FieldMetadata fieldMetadata = classMetadata.getFieldMetadata(fieldNode.name); if (fieldMetadata.hasFieldGranularity()) { String referenceDesc = findReferenceDesc(fieldNode.desc); FieldNode fixedFieldNode = new FieldNode( ACC_SYNTHETIC + ACC_FINAL + ACC_PUBLIC, fieldNode.name, referenceDesc, null, // signature null // value ); fields.add(fixedFieldNode); } else { fields.add(fieldNode); } } classNode.fields = fields; }
private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) { InsnList instructions = new InsnList(); for (int k = 0; k < originalMethod.instructions.size(); k++) { AbstractInsnNode originalInsn = originalMethod.instructions.get(k); switch (originalInsn.getOpcode()) { // the put on the field granular field is transformed to a fieldref.set case PUTFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; ClassMetadata ownerMetadata = metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner); FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (fieldMetadata.hasFieldGranularity()) { boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc()); if (fieldIsCategory2) { // value(category2), owner,.. instructions.add(new InsnNode(DUP2_X1)); // [value(category2), owner, value(category2),...] instructions.add(new InsnNode(POP2)); // [owner, value(category2), ...] } else { // [value(category1), owner, instructions.add(new InsnNode(SWAP)); // [owner, value(category1),.. } String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); if (fieldIsCategory2) { // [owner, value(category2),.. instructions.add(new InsnNode(DUP_X2)); // [owner, value(category2), owner instructions.add(new InsnNode(POP)); // [value(category2), owner } else { // [owner, value(category1) instructions.add(new InsnNode(SWAP)); // [value(category1), owner.. } // call the set if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { String objectDesc = Type.getDescriptor(Object.class); MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", objectDesc, objectDesc)); instructions.add(methodInsn); } else { MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc())); instructions.add(methodInsn); } // pop the unused return value of the set. if (fieldIsCategory2) { instructions.add(new InsnNode(POP2)); } else { instructions.add(new InsnNode(POP)); } } else { instructions.add(originalInsn.clone(cloneMap)); } } break; // the get on the field granular field is transformed to a fieldref.get case GETFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; FieldMetadata fieldMetadata = metadataRepository .loadClassMetadata(classLoader, fieldInsn.owner) .getFieldMetadata(fieldInsn.name); if (!fieldMetadata.hasFieldGranularity()) { // if it is not getter on a field granular field instructions.add(originalInsn.clone(cloneMap)); } else { // it is a getter on a field granular field. String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); // place the fieldref on the stack. instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", getDescriptor(Object.class)))); if (!originalFieldType.equals(Type.getType(Object.class))) { instructions.add( new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName())); } } else { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", fieldMetadata.getDesc()))); } } } break; default: instructions.add(originalInsn.clone(cloneMap)); break; } } return instructions; }