100 private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class); |
100 private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class); |
101 private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class); |
101 private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class); |
102 private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class); |
102 private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class); |
103 private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class); |
103 private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class); |
104 private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class); |
104 private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class); |
|
105 private static final Type TYPE_OBJECT = Type.getType(Object.class); |
105 private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]); |
106 private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]); |
106 private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]); |
107 private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]); |
107 private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]); |
108 private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]); |
108 private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]); |
109 private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]); |
109 private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]); |
110 private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]); |
115 private final List<SettingInfo> settingInfos; |
116 private final List<SettingInfo> settingInfos; |
116 private final List<FieldInfo> fieldInfos;; |
117 private final List<FieldInfo> fieldInfos;; |
117 private final Method writeMethod; |
118 private final Method writeMethod; |
118 private final String eventHandlerXInternalName; |
119 private final String eventHandlerXInternalName; |
119 private final String eventName; |
120 private final String eventName; |
|
121 private final boolean untypedEventHandler; |
120 private boolean guardHandlerReference; |
122 private boolean guardHandlerReference; |
121 private Class<?> superClass; |
123 private Class<?> superClass; |
122 |
124 |
123 EventInstrumentation(Class<?> superClass, byte[] bytes, long id) { |
125 EventInstrumentation(Class<?> superClass, byte[] bytes, long id) { |
124 this.superClass = superClass; |
126 this.superClass = superClass; |
125 this.classNode = createClassNode(bytes); |
127 this.classNode = createClassNode(bytes); |
126 this.settingInfos = buildSettingInfos(superClass, classNode); |
128 this.settingInfos = buildSettingInfos(superClass, classNode); |
127 this.fieldInfos = buildFieldInfos(superClass, classNode); |
129 this.fieldInfos = buildFieldInfos(superClass, classNode); |
|
130 this.untypedEventHandler = hasUntypedHandler(); |
128 this.writeMethod = makeWriteMethod(fieldInfos); |
131 this.writeMethod = makeWriteMethod(fieldInfos); |
129 this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id)); |
132 this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id)); |
130 String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class); |
133 String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class); |
131 this.eventName = n == null ? classNode.name.replace("/", ".") : n; |
134 this.eventName = n == null ? classNode.name.replace("/", ".") : n; |
132 |
135 } |
|
136 |
|
137 private boolean hasUntypedHandler() { |
|
138 for (FieldNode field : classNode.fields) { |
|
139 if (FIELD_EVENT_HANDLER.equals(field.name)) { |
|
140 return field.desc.equals(TYPE_OBJECT.getDescriptor()); |
|
141 } |
|
142 } |
|
143 throw new InternalError("Class missing handler field"); |
133 } |
144 } |
134 |
145 |
135 public String getClassName() { |
146 public String getClassName() { |
136 return classNode.name.replace("/","."); |
147 return classNode.name.replace("/","."); |
137 } |
148 } |
262 // in Java, instead of in native. It also means code for adding implicit |
272 // in Java, instead of in native. It also means code for adding implicit |
263 // fields for native can be reused by Java. |
273 // fields for native can be reused by Java. |
264 fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name)); |
274 fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name)); |
265 fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name)); |
275 fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name)); |
266 for (FieldNode field : classNode.fields) { |
276 for (FieldNode field : classNode.fields) { |
267 String className = Type.getType(field.desc).getClassName(); |
277 if (!fieldSet.contains(field.name) && isValidField(field.access, Type.getType(field.desc).getClassName())) { |
268 if (!fieldSet.contains(field.name) && isValidField(field.access, className)) { |
|
269 FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name); |
278 FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name); |
270 fieldInfos.add(fi); |
279 fieldInfos.add(fi); |
271 fieldSet.add(field.name); |
280 fieldSet.add(field.name); |
272 } |
281 } |
273 } |
282 } |
274 for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) { |
283 for (Class<?> c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) { |
275 for (Field field : c.getDeclaredFields()) { |
284 for (Field field : c.getDeclaredFields()) { |
276 // skip private field in base classes |
285 // skip private field in base classes |
277 if (!Modifier.isPrivate(field.getModifiers())) { |
286 if (!Modifier.isPrivate(field.getModifiers())) { |
278 if (isValidField(field.getModifiers(), field.getType().getName())) { |
287 if (isValidField(field.getModifiers(), field.getType().getName())) { |
279 String fieldName = field.getName(); |
288 String fieldName = field.getName(); |
319 private void makeInstrumented() { |
328 private void makeInstrumented() { |
320 // MyEvent#isEnabled() |
329 // MyEvent#isEnabled() |
321 updateMethod(METHOD_IS_ENABLED, methodVisitor -> { |
330 updateMethod(METHOD_IS_ENABLED, methodVisitor -> { |
322 Label nullLabel = new Label(); |
331 Label nullLabel = new Label(); |
323 if (guardHandlerReference) { |
332 if (guardHandlerReference) { |
324 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor()); |
333 getEventHandler(methodVisitor); |
325 methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel); |
334 methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel); |
326 } |
335 } |
327 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor()); |
336 getEventHandler(methodVisitor); |
328 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED); |
337 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED); |
329 methodVisitor.visitInsn(Opcodes.IRETURN); |
338 methodVisitor.visitInsn(Opcodes.IRETURN); |
330 if (guardHandlerReference) { |
339 if (guardHandlerReference) { |
331 methodVisitor.visitLabel(nullLabel); |
340 methodVisitor.visitLabel(nullLabel); |
332 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
341 methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
406 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false); |
415 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false); |
407 Label end = new Label(); |
416 Label end = new Label(); |
408 // eventHandler.write(...); |
417 // eventHandler.write(...); |
409 // } |
418 // } |
410 methodVisitor.visitJumpInsn(Opcodes.IFEQ, end); |
419 methodVisitor.visitJumpInsn(Opcodes.IFEQ, end); |
411 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); |
420 getEventHandler(methodVisitor); |
412 |
421 |
413 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); |
422 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); |
414 for (FieldInfo fi : fieldInfos) { |
423 for (FieldInfo fi : fieldInfos) { |
415 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); |
424 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); |
416 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor); |
425 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor); |
424 }); |
433 }); |
425 |
434 |
426 // MyEvent#shouldCommit() |
435 // MyEvent#shouldCommit() |
427 updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> { |
436 updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> { |
428 Label fail = new Label(); |
437 Label fail = new Label(); |
429 // if (!eventHandler.shoouldCommit(duration) goto fail; |
438 // if (!eventHandler.shouldCommit(duration) goto fail; |
430 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); |
439 getEventHandler(methodVisitor); |
431 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); |
440 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); |
432 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); |
441 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); |
433 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT); |
442 ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT); |
434 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); |
443 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); |
435 for (SettingInfo si : settingInfos) { |
444 for (SettingInfo si : settingInfos) { |
436 // if (!settingsMethod(eventHandler.settingX)) goto fail; |
445 // if (!settingsMethod(eventHandler.settingX)) goto fail; |
437 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); |
446 methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); |
438 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); |
447 if (untypedEventHandler) { |
|
448 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor()); |
|
449 } else { |
|
450 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); |
|
451 } |
439 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); |
452 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); |
440 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor()); |
453 methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor()); |
441 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName); |
454 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName); |
442 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false); |
455 methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false); |
443 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); |
456 methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); |
448 // return false |
461 // return false |
449 methodVisitor.visitLabel(fail); |
462 methodVisitor.visitLabel(fail); |
450 methodVisitor.visitInsn(Opcodes.ICONST_0); |
463 methodVisitor.visitInsn(Opcodes.ICONST_0); |
451 methodVisitor.visitInsn(Opcodes.IRETURN); |
464 methodVisitor.visitInsn(Opcodes.IRETURN); |
452 }); |
465 }); |
|
466 } |
|
467 |
|
468 private void getEventHandler(MethodVisitor methodVisitor) { |
|
469 if (untypedEventHandler) { |
|
470 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor()); |
|
471 methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_HANDLER.getInternalName()); |
|
472 } else { |
|
473 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); |
|
474 } |
453 } |
475 } |
454 |
476 |
455 private void makeUninstrumented() { |
477 private void makeUninstrumented() { |
456 updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); |
478 updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); |
457 updateExistingWithReturnFalse(METHOD_IS_ENABLED); |
479 updateExistingWithReturnFalse(METHOD_IS_ENABLED); |