--- /dev/null 2020-01-02 04:43:18.583999853 +0000 +++ new/src/share/classes/jdk/jfr/internal/EventHandlerProxyCreator.java 2020-01-30 06:26:13.066624380 +0000 @@ -0,0 +1,126 @@ +/* + * 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(); + } +}