protected void enhanceAttributesAccess( CtClass managedCtClass, IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) { final ConstPool constPool = managedCtClass.getClassFile().getConstPool(); for (Object oMethod : managedCtClass.getClassFile().getMethods()) { final MethodInfo methodInfo = (MethodInfo) oMethod; final String methodName = methodInfo.getName(); // skip methods added by enhancement and abstract methods (methods without any code) if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) { continue; } try { final CodeIterator itr = methodInfo.getCodeAttribute().iterator(); while (itr.hasNext()) { final int index = itr.next(); final int op = itr.byteAt(index); if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) { continue; } final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1)); final PersistentAttributeAccessMethods attributeMethods = attributeDescriptorMap.get(fieldName); // its not a field we have enhanced for interception, so skip it if (attributeMethods == null) { continue; } // System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName, // methodName ); log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName); if (op == Opcode.GETFIELD) { final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getReader()); itr.writeByte(Opcode.INVOKESPECIAL, index); itr.write16bit(methodIndex, index + 1); } else { final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter()); itr.writeByte(Opcode.INVOKESPECIAL, index); itr.write16bit(methodIndex, index + 1); } } methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo)); } catch (BadBytecode bb) { final String msg = String.format( "Unable to perform field access transformation in method [%s]", methodName); throw new EnhancementException(msg, bb); } } }
/* 94: */ /* 95: */ protected int match( int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp) /* 96: */ throws BadBytecode /* 97: */ { /* 98:110 */ if (this.newIndex == 0) /* 99: */ { /* 100:111 */ int nt = cp.addNameAndTypeInfo(cp.addUtf8Info(this.newMethodname), typedesc); /* 101: */ /* 102:113 */ int ci = cp.addClassInfo(this.newClassname); /* 103:114 */ if (c == 185) /* 104: */ { /* 105:115 */ this.newIndex = cp.addInterfaceMethodrefInfo(ci, nt); /* 106: */ } /* 107: */ else /* 108: */ { /* 109:117 */ if ((this.newMethodIsPrivate) && (c == 182)) { /* 110:118 */ iterator.writeByte(183, pos); /* 111: */ } /* 112:120 */ this.newIndex = cp.addMethodrefInfo(ci, nt); /* 113: */ } /* 114:123 */ this.constPool = cp; /* 115: */ } /* 116:126 */ iterator.write16bit(this.newIndex, pos + 1); /* 117:127 */ return pos; /* 118: */ }
/** * @param lessThan If the index of the local variable is less than this value, it does not change. * Otherwise, the index is increased. * @param delta the indexes of the local variables are increased by this value. */ private static void shiftIndex(CodeIterator ci, int lessThan, int delta) throws BadBytecode { int index = ci.next(); int opcode = ci.byteAt(index); if (opcode < ILOAD) return; else if (opcode < IASTORE) { if (opcode < ILOAD_0) { // iload, lload, fload, dload, aload shiftIndex8(ci, index, opcode, lessThan, delta); } else if (opcode < IALOAD) { // iload_0, ..., aload_3 shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD); } else if (opcode < ISTORE) return; else if (opcode < ISTORE_0) { // istore, lstore, ... shiftIndex8(ci, index, opcode, lessThan, delta); } else { // istore_0, ..., astore_3 shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE); } } else if (opcode == IINC) { int var = ci.byteAt(index + 1); if (var < lessThan) return; var += delta; if (var < 0x100) ci.writeByte(var, index + 1); else { int plus = (byte) ci.byteAt(index + 2); int pos = ci.insertExGap(3); ci.writeByte(WIDE, pos - 3); ci.writeByte(IINC, pos - 2); ci.write16bit(var, pos - 1); ci.write16bit(plus, pos + 1); } } else if (opcode == RET) shiftIndex8(ci, index, opcode, lessThan, delta); else if (opcode == WIDE) { int var = ci.u16bitAt(index + 2); if (var < lessThan) return; var += delta; ci.write16bit(var, index + 2); } }
protected void enhanceAttributesAccess(Map<String, CtField> fieldsMap, CtClass managedCtClass) throws Exception { final ConstPool constPool = managedCtClass.getClassFile().getConstPool(); final ClassPool classPool = managedCtClass.getClassPool(); for (Object oMethod : managedCtClass.getClassFile().getMethods()) { final MethodInfo methodInfo = (MethodInfo) oMethod; final String methodName = methodInfo.getName(); // skip methods added by enhancement, and abstract methods (methods without any code) if (methodName.startsWith(DROOLS_PREFIX) || methodInfo.getCodeAttribute() == null) { continue; } try { final CodeIterator itr = methodInfo.getCodeAttribute().iterator(); while (itr.hasNext()) { final int index = itr.next(); final int op = itr.byteAt(index); if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) { continue; } final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1)); CtField ctField = fieldsMap.get(fieldName); if (ctField == null) { continue; } // if we are in constructors, only need to intercept assignment statement for Reactive // Collection/List/... (regardless they may be final) if (methodInfo.isConstructor() && !(isCtFieldACollection(ctField))) { continue; } if (op == Opcode.PUTFIELD) { // addMethod is a safe add, if constant already present it return the existing value // without adding. final int methodIndex = addMethod(constPool, writeMethods.get(fieldName)); itr.writeByte(Opcode.INVOKEVIRTUAL, index); itr.write16bit(methodIndex, index + 1); } } methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo)); } catch (BadBytecode bb) { final String msg = String.format( "Unable to perform field access transformation in method [%s]", methodName); throw new Exception(msg, bb); } } }
private static void shiftIndex8(CodeIterator ci, int index, int opcode, int lessThan, int delta) throws BadBytecode { int var = ci.byteAt(index + 1); if (var < lessThan) return; var += delta; if (var < 0x100) ci.writeByte(var, index + 1); else { int pos = ci.insertExGap(2); ci.writeByte(WIDE, pos - 2); ci.writeByte(opcode, pos - 1); ci.write16bit(var, pos); } }
private static void shiftIndex0( CodeIterator ci, int index, int opcode, int lessThan, int delta, int opcode_i_0, int opcode_i) throws BadBytecode { int var = (opcode - opcode_i_0) % 4; if (var < lessThan) return; var += delta; if (var < 4) ci.writeByte(opcode + delta, index); else { opcode = (opcode - opcode_i_0) / 4 + opcode_i; if (var < 0x100) { int pos = ci.insertExGap(1); ci.writeByte(opcode, pos - 1); ci.writeByte(var, pos); } else { int pos = ci.insertExGap(3); ci.writeByte(WIDE, pos - 1); ci.writeByte(opcode, pos); ci.write16bit(var, pos + 1); } } }
/** * Replace access to fields of entities (for example, entity.field) with a call to the enhanced * getter / setter (in this example, entity.$$_hibernate_read_field()). It's assumed that the * target entity is enhanced as well. * * @param managedCtClass Class to enhance */ public void enhanceFieldAccess(CtClass managedCtClass) { final ConstPool constPool = managedCtClass.getClassFile().getConstPool(); for (Object oMethod : managedCtClass.getClassFile().getMethods()) { final MethodInfo methodInfo = (MethodInfo) oMethod; final String methodName = methodInfo.getName(); // skip methods added by enhancement and abstract methods (methods without any code) if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) { continue; } try { final CodeIterator itr = methodInfo.getCodeAttribute().iterator(); while (itr.hasNext()) { int index = itr.next(); int op = itr.byteAt(index); if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) { continue; } String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1)); String fieldClassName = constPool.getClassInfo(constPool.getFieldrefClass(itr.u16bitAt(index + 1))); CtClass targetCtClass = this.classPool.getCtClass(fieldClassName); if (!enhancementContext.isEntityClass(targetCtClass) && !enhancementContext.isCompositeClass(targetCtClass)) { continue; } if (targetCtClass == managedCtClass || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName)) || "this$0".equals(fieldName)) { continue; } log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName); if (op == Opcode.GETFIELD) { int fieldReaderMethodIndex = constPool.addMethodrefInfo( constPool.addClassInfo(fieldClassName), EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName, "()" + constPool.getFieldrefType(itr.u16bitAt(index + 1))); itr.writeByte(Opcode.INVOKEVIRTUAL, index); itr.write16bit(fieldReaderMethodIndex, index + 1); } else { int fieldWriterMethodIndex = constPool.addMethodrefInfo( constPool.addClassInfo(fieldClassName), EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName, "(" + constPool.getFieldrefType(itr.u16bitAt(index + 1)) + ")V"); itr.writeByte(Opcode.INVOKEVIRTUAL, index); itr.write16bit(fieldWriterMethodIndex, index + 1); } } methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo)); } catch (BadBytecode bb) { final String msg = String.format( "Unable to perform field access transformation in method [%s]", methodName); throw new EnhancementException(msg, bb); } catch (NotFoundException nfe) { final String msg = String.format( "Unable to perform field access transformation in method [%s]", methodName); throw new EnhancementException(msg, nfe); } } }