Last active
August 29, 2015 14:08
-
-
Save serkan-ozal/4b88aa21254c586bae50 to your computer and use it in GitHub Desktop.
A piece of code from Jillegal 3.0 to instrument all non-primitive field assignments in OffHeap object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protected <T> void instrumentNonPrimitiveFieldAssignments(final Class<T> elementType) { | |
try { | |
Jillegal.init(); | |
final InstrumentService instrumenterService = InstrumentServiceFactory.getInstrumentService(); | |
final String ownerClassDesc = elementType.getName().replace(".", "/"); | |
final Set<String> ownerClassDescSet = new HashSet<String>(); | |
ownerClassDescSet.add(ownerClassDesc); | |
for ( Class<T> parentClass = (Class<T>) elementType.getSuperclass(); | |
parentClass != null && !parentClass.equals(Object.class); | |
parentClass = (Class<T>) parentClass.getSuperclass()) { | |
ownerClassDescSet.add(parentClass.getName().replace(".", "/")); | |
} | |
ClassReader cr = new ClassReader(elementType.getName()); | |
ClassWriter cw = new ClassWriter(ClassReader.SKIP_DEBUG) { | |
@Override | |
public MethodVisitor visitMethod(final int access, final String name, | |
final String desc, final String signature, final String[] exceptions) { | |
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); | |
return | |
new MethodAdapter(mv) { | |
public void visitFieldInsn(final int opcode, final String owner, | |
final String name, final String desc) { | |
if ( opcode == Opcodes.PUTFIELD && | |
ownerClassDescSet.contains(owner) && | |
(desc.startsWith("L") && desc.endsWith(";"))) { | |
int fieldOffset = | |
(int) JvmUtil.getUnsafe(). | |
objectFieldOffset(ReflectionUtil.getField(elementType, name)); | |
// Current operand stack snapshot: ..., <this>, <value_to_set> | |
super.visitInsn(Opcode.SWAP); | |
// Current operand stack snapshot: | |
// ..., <value_to_set>, <this> | |
super.visitInsn(Opcodes.POP); | |
// Current operand stack snapshot: | |
// ..., <value_to_set> | |
super.visitMethodInsn( // Call "getProperties" method of "java.lang.System" class | |
Opcodes.INVOKESTATIC, | |
"java/lang/System", | |
"getProperties", | |
"()Ljava/util/Properties;"); | |
super.visitLdcInsn( | |
DirectMemoryServiceFactory. | |
DIRECT_MEMORY_SERVICE_$_SET_OBJECT_FIELD_ACCESSOR); | |
super.visitMethodInsn( // Call "get" method of "java/util/Properties" instance | |
Opcodes.INVOKEVIRTUAL, | |
"java/util/Properties", | |
"get", | |
"(Ljava/lang/Object;)Ljava/lang/Object;"); | |
// Current operand stack snapshot: | |
// ..., <value_to_set>, <DirectMemoryService_setObjectField> | |
super.visitTypeInsn( | |
Opcode.CHECKCAST, | |
PropertyChangeSupport.class.getName().replace(".", "/")); | |
// Current operand stack snapshot: | |
// ..., <value_to_set>, <DirectMemoryService_setObjectField> | |
super.visitInsn(Opcode.SWAP); | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <value_to_set> | |
super.visitInsn(Opcode.ACONST_NULL); | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <value_to_set>, <null> | |
super.visitInsn(Opcode.SWAP); | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <null>, <value_to_set> | |
super.visitLdcInsn(fieldOffset); // offset of field | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <null>, <value_to_set>, <field_offset> | |
super.visitInsn(Opcode.SWAP); | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <null>, <field_offset>, <value_to_set> | |
super.visitVarInsn(Opcodes.ALOAD, 0); // this | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <null>, <field_offset>, <value_to_set>, <this> | |
super.visitInsn(Opcode.SWAP); | |
// Current operand stack snapshot: | |
// ..., <DirectMemoryService_setObjectField>, <null>, <field_offset>, <this>, <value_to_set>, | |
// Now <field_offset>, <this>, <value_to_set> are the parameters in this order | |
// to be passed for "setObjectField" method "DirectMemoryService" instance | |
super.visitMethodInsn( // Call "fireIndexedPropertyChange" method of "java/beans/PropertyChangeSupport" instance | |
Opcodes.INVOKEVIRTUAL, | |
PropertyChangeSupport.class.getName().replace(".", "/"), | |
"fireIndexedPropertyChange", | |
"(Ljava/lang/String;ILjava/lang/Object;Ljava/lang/Object;)V"); | |
logger.debug("Instrumenting assignment to field \"" + name + | |
"\" in class " + elementType.getName()); | |
} | |
else { | |
super.visitFieldInsn(opcode, owner, name, desc); | |
} | |
} | |
}; | |
} | |
}; | |
cr.accept(cw, ClassReader.SKIP_DEBUG); | |
byte[] instrumentedBytecodes = cw.toByteArray(); | |
instrumenterService.redefineClass(elementType, instrumentedBytecodes); | |
logger.info("Instrumented class " + elementType.getName() + " for non-primitive field assignment"); | |
} | |
catch (Throwable t) { | |
t.printStackTrace(); | |
logger.error("Error occured while instrumenting non-primitive field assignments for class " + | |
elementType.getName(), t); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment