src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java
changeset 52334 a181612f0715
parent 50113 caf115bb98ad
child 52698 ca6b58b8ffc5
equal deleted inserted replaced
52333:c401c536cea1 52334:a181612f0715
   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     }
   223                         }
   234                         }
   224                     }
   235                     }
   225                 }
   236                 }
   226             }
   237             }
   227         }
   238         }
   228         for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
   239         for (Class<?> c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) {
   229             for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
   240             for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
   230                 if (!methodSet.contains(method.getName())) {
   241                 if (!methodSet.contains(method.getName())) {
   231                     // skip private method in base classes
   242                     // skip private method in base classes
   232                     if (!Modifier.isPrivate(method.getModifiers())) {
   243                     if (!Modifier.isPrivate(method.getModifiers())) {
   233                         if (method.getReturnType().equals(Boolean.TYPE)) {
   244                         if (method.getReturnType().equals(Boolean.TYPE)) {
   247                     }
   258                     }
   248                 }
   259                 }
   249             }
   260             }
   250         }
   261         }
   251         return settingInfos;
   262         return settingInfos;
   252 
       
   253     }
   263     }
   254 
   264 
   255     private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
   265     private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
   256         Set<String> fieldSet = new HashSet<>();
   266         Set<String> fieldSet = new HashSet<>();
   257         List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size());
   267         List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size());
   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);