src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java
changeset 50113 caf115bb98ad
child 52015 821bfc24d750
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.jfr.internal;
       
    27 
       
    28 import java.util.List;
       
    29 import java.util.concurrent.atomic.AtomicLong;
       
    30 
       
    31 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
       
    32 import jdk.internal.org.objectweb.asm.ClassWriter;
       
    33 import jdk.internal.org.objectweb.asm.Label;
       
    34 import jdk.internal.org.objectweb.asm.MethodVisitor;
       
    35 import jdk.internal.org.objectweb.asm.Opcodes;
       
    36 import jdk.internal.org.objectweb.asm.Type;
       
    37 import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;
       
    38 import jdk.internal.org.objectweb.asm.commons.Method;
       
    39 import jdk.jfr.AnnotationElement;
       
    40 import jdk.jfr.Event;
       
    41 import jdk.jfr.ValueDescriptor;
       
    42 
       
    43 
       
    44 // Helper class for building dynamic events
       
    45 public final class EventClassBuilder {
       
    46 
       
    47     private static final Type TYPE_EVENT = Type.getType(Event.class);
       
    48     private static final Type TYPE_IOBE = Type.getType(IndexOutOfBoundsException.class);
       
    49     private static final Method DEFAULT_CONSTRUCTOR = Method.getMethod("void <init> ()");
       
    50     private static final Method SET_METHOD = Method.getMethod("void set (int, java.lang.Object)");
       
    51     private static final AtomicLong idCounter = new AtomicLong();
       
    52     private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
       
    53     private final String fullClassName;
       
    54     private final Type type;
       
    55     private final List<ValueDescriptor> fields;
       
    56     private final List<AnnotationElement> annotationElements;
       
    57 
       
    58     public EventClassBuilder(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
       
    59         this.fullClassName = "jdk.jfr.DynamicEvent" + idCounter.incrementAndGet();
       
    60         this.type = Type.getType(fullClassName.replace(".", "/"));
       
    61         this.fields = fields;
       
    62         this.annotationElements = annotationElements;
       
    63     }
       
    64 
       
    65     public Class<? extends Event> build() {
       
    66         buildClassInfo();
       
    67         buildConstructor();
       
    68         buildFields();
       
    69         buildSetMethod();
       
    70         endClass();
       
    71         byte[] bytes = classWriter.toByteArray();
       
    72         ASMToolkit.logASM(fullClassName, bytes);
       
    73         return SecuritySupport.defineClass(type.getInternalName(), bytes, Event.class.getClassLoader()).asSubclass(Event.class);
       
    74     }
       
    75 
       
    76     private void endClass() {
       
    77         classWriter.visitEnd();
       
    78     }
       
    79 
       
    80     private void buildSetMethod() {
       
    81         GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, SET_METHOD, null, null, classWriter);
       
    82         int index = 0;
       
    83         for (ValueDescriptor v : fields) {
       
    84             ga.loadArg(0);
       
    85             ga.visitLdcInsn(index);
       
    86             Label notEqual = new Label();
       
    87             ga.ifICmp(GeneratorAdapter.NE, notEqual);
       
    88             ga.loadThis();
       
    89             ga.loadArg(1);
       
    90             Type fieldType = ASMToolkit.toType(v);
       
    91             ga.unbox(ASMToolkit.toType(v));
       
    92             ga.putField(type, v.getName(), fieldType);
       
    93             ga.visitInsn(Opcodes.RETURN);
       
    94             ga.visitLabel(notEqual);
       
    95             index++;
       
    96         }
       
    97         ga.throwException(TYPE_IOBE, "Index must between 0 and " + fields.size());
       
    98         ga.endMethod();
       
    99     }
       
   100 
       
   101     private void buildConstructor() {
       
   102         MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
       
   103         mv.visitIntInsn(Opcodes.ALOAD, 0);
       
   104         ASMToolkit.invokeSpecial(mv, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR);
       
   105         mv.visitInsn(Opcodes.RETURN);
       
   106         mv.visitMaxs(0, 0);
       
   107     }
       
   108 
       
   109     private void buildClassInfo() {
       
   110         String internalSuperName = ASMToolkit.getInternalName(Event.class.getName());
       
   111         String internalClassName = type.getInternalName();
       
   112         classWriter.visit(52, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
       
   113 
       
   114         for (AnnotationElement a : annotationElements) {
       
   115             String descriptor = ASMToolkit.getDescriptor(a.getTypeName());
       
   116             AnnotationVisitor av = classWriter.visitAnnotation(descriptor, true);
       
   117             for (ValueDescriptor v : a.getValueDescriptors()) {
       
   118                 Object value = a.getValue(v.getName());
       
   119                 String name = v.getName();
       
   120                 if (v.isArray()) {
       
   121                     AnnotationVisitor arrayVisitor = av.visitArray(name);
       
   122                     Object[] array = (Object[]) value;
       
   123                     for (int i = 0; i < array.length; i++) {
       
   124                         arrayVisitor.visit(null, array[i]);
       
   125                     }
       
   126                     arrayVisitor.visitEnd();
       
   127                 } else {
       
   128                     av.visit(name, value);
       
   129                 }
       
   130             }
       
   131             av.visitEnd();
       
   132         }
       
   133     }
       
   134 
       
   135     private void buildFields() {
       
   136         for (ValueDescriptor v : fields) {
       
   137             String internal = ASMToolkit.getDescriptor(v.getTypeName());
       
   138             classWriter.visitField(Opcodes.ACC_PRIVATE, v.getName(), internal, null, null);
       
   139             // No need to store annotations on field since they will be replaced anyway.
       
   140         }
       
   141     }
       
   142 }