--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
+import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;
+import jdk.internal.org.objectweb.asm.commons.Method;
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.ValueDescriptor;
+
+
+// Helper class for building dynamic events
+public final class EventClassBuilder {
+
+ private static final Type TYPE_EVENT = Type.getType(Event.class);
+ private static final Type TYPE_IOBE = Type.getType(IndexOutOfBoundsException.class);
+ private static final Method DEFAULT_CONSTRUCTOR = Method.getMethod("void <init> ()");
+ private static final Method SET_METHOD = Method.getMethod("void set (int, java.lang.Object)");
+ private static final AtomicLong idCounter = new AtomicLong();
+ private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+ private final String fullClassName;
+ private final Type type;
+ private final List<ValueDescriptor> fields;
+ private final List<AnnotationElement> annotationElements;
+
+ public EventClassBuilder(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
+ this.fullClassName = "jdk.jfr.DynamicEvent" + idCounter.incrementAndGet();
+ this.type = Type.getType(fullClassName.replace(".", "/"));
+ this.fields = fields;
+ this.annotationElements = annotationElements;
+ }
+
+ public Class<? extends Event> build() {
+ buildClassInfo();
+ buildConstructor();
+ buildFields();
+ buildSetMethod();
+ endClass();
+ byte[] bytes = classWriter.toByteArray();
+ ASMToolkit.logASM(fullClassName, bytes);
+ return SecuritySupport.defineClass(type.getInternalName(), bytes, Event.class.getClassLoader()).asSubclass(Event.class);
+ }
+
+ private void endClass() {
+ classWriter.visitEnd();
+ }
+
+ private void buildSetMethod() {
+ GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, SET_METHOD, null, null, classWriter);
+ int index = 0;
+ for (ValueDescriptor v : fields) {
+ ga.loadArg(0);
+ ga.visitLdcInsn(index);
+ Label notEqual = new Label();
+ ga.ifICmp(GeneratorAdapter.NE, notEqual);
+ ga.loadThis();
+ ga.loadArg(1);
+ Type fieldType = ASMToolkit.toType(v);
+ ga.unbox(ASMToolkit.toType(v));
+ ga.putField(type, v.getName(), fieldType);
+ ga.visitInsn(Opcodes.RETURN);
+ ga.visitLabel(notEqual);
+ index++;
+ }
+ ga.throwException(TYPE_IOBE, "Index must between 0 and " + fields.size());
+ ga.endMethod();
+ }
+
+ private void buildConstructor() {
+ MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
+ mv.visitIntInsn(Opcodes.ALOAD, 0);
+ ASMToolkit.invokeSpecial(mv, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(0, 0);
+ }
+
+ private void buildClassInfo() {
+ String internalSuperName = ASMToolkit.getInternalName(Event.class.getName());
+ String internalClassName = type.getInternalName();
+ classWriter.visit(52, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
+
+ for (AnnotationElement a : annotationElements) {
+ String descriptor = ASMToolkit.getDescriptor(a.getTypeName());
+ AnnotationVisitor av = classWriter.visitAnnotation(descriptor, true);
+ for (ValueDescriptor v : a.getValueDescriptors()) {
+ Object value = a.getValue(v.getName());
+ String name = v.getName();
+ if (v.isArray()) {
+ AnnotationVisitor arrayVisitor = av.visitArray(name);
+ Object[] array = (Object[]) value;
+ for (int i = 0; i < array.length; i++) {
+ arrayVisitor.visit(null, array[i]);
+ }
+ arrayVisitor.visitEnd();
+ } else {
+ av.visit(name, value);
+ }
+ }
+ av.visitEnd();
+ }
+ }
+
+ private void buildFields() {
+ for (ValueDescriptor v : fields) {
+ String internal = ASMToolkit.getDescriptor(v.getTypeName());
+ classWriter.visitField(Opcodes.ACC_PRIVATE, v.getName(), internal, null, null);
+ // No need to store annotations on field since they will be replaced anyway.
+ }
+ }
+}