/* * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Red Hat, Inc. * * 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.StringJoiner; import jdk.internal.org.objectweb.asm.ClassWriter; 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.Method; import jdk.jfr.Event; import jdk.jfr.EventType; import jdk.jfr.internal.handlers.EventHandler; /* * Generates an EventHandler subclass dynamically, named EventHandlerProxy. * EventHandlerProxy is located in a publicly accessible package (jdk.jfr) * and is used as a superclass for classes generated by EventHandlerCreator. * The rationale behind this scheme is to block access to jdk.jfr.internal * package and sub-packages when there is a SecurityManager installed, while * allowing application-defined event classes to invoke the required internal * APIs. */ final class EventHandlerProxyCreator { private static final int CLASS_VERSION = 52; private final static Type TYPE_EVENT_TYPE = Type.getType(EventType.class); private final static Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class); private final static String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V"; private final static Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("", DESCRIPTOR_EVENT_HANDLER); private final static String DESCRIPTOR_TIME_STAMP = "()" + Type.LONG_TYPE.getDescriptor(); private final static Method METHOD_TIME_STAMP = new Method("timestamp", DESCRIPTOR_TIME_STAMP); private final static String DESCRIPTOR_DURATION = "(" + Type.LONG_TYPE.getDescriptor() + ")" + Type.LONG_TYPE.getDescriptor(); private final static Method METHOD_DURATION = new Method("duration", DESCRIPTOR_DURATION); private final static ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); private final static String className = "jdk.jfr.proxy.internal.EventHandlerProxy"; private final static String internalClassName = ASMToolkit.getInternalName(className); // Create the Proxy class instance after all the previous static fields were initialized (textual order) static final Class proxyClass = EventHandlerProxyCreator.makeEventHandlerProxyClass(); static void ensureInitialized() { // trigger clinit which will setup the EventHandlerProxy class. } public static Class makeEventHandlerProxyClass() { buildClassInfo(); buildConstructor(); buildTimestampMethod(); buildDurationMethod(); byte[] bytes = classWriter.toByteArray(); ASMToolkit.logASM(className, bytes); return SecuritySupport.defineClass(className, bytes, Event.class.getClassLoader()).asSubclass(EventHandler.class); } private static void buildConstructor() { MethodVisitor mv = classWriter.visitMethod(0x0, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(), null, null); mv.visitVarInsn(Opcodes.ALOAD, 0); // this mv.visitVarInsn(Opcodes.ILOAD, 1); // registered mv.visitVarInsn(Opcodes.ALOAD, 2); // event type mv.visitVarInsn(Opcodes.ALOAD, 3); // event control mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(EventHandler.class), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private static void buildClassInfo() { String internalSuperName = ASMToolkit.getInternalName(EventHandler.class.getName()); classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null); } private static void buildTimestampMethod() { MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), null, null); mv.visitCode(); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); mv.visitInsn(Opcodes.LRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private static void buildDurationMethod() { MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.LLOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), false); mv.visitInsn(Opcodes.LRETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } private static String makeConstructorDescriptor() { StringJoiner constructordescriptor = new StringJoiner("", "(", ")V"); constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor()); constructordescriptor.add(Type.getType(EventType.class).getDescriptor()); constructordescriptor.add(Type.getType(EventControl.class).getDescriptor()); return constructordescriptor.toString(); } }