1 /*
   2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2019, Red Hat, Inc.
   4  *
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 
  28 package jdk.jfr.internal;
  29 
  30 import java.util.StringJoiner;
  31 
  32 import jdk.internal.org.objectweb.asm.ClassWriter;
  33 import jdk.internal.org.objectweb.asm.MethodVisitor;
  34 import jdk.internal.org.objectweb.asm.Opcodes;
  35 import jdk.internal.org.objectweb.asm.Type;
  36 import jdk.internal.org.objectweb.asm.commons.Method;
  37 import jdk.jfr.Event;
  38 import jdk.jfr.EventType;
  39 import jdk.jfr.internal.handlers.EventHandler;
  40 
  41 /*
  42  * Generates an EventHandler subclass dynamically, named EventHandlerProxy.
  43  * EventHandlerProxy is located in a publicly accessible package (jdk.jfr)
  44  * and is used as a superclass for classes generated by EventHandlerCreator.
  45  * The rationale behind this scheme is to block access to jdk.jfr.internal
  46  * package and sub-packages when there is a SecurityManager installed, while
  47  * allowing application-defined event classes to invoke the required internal
  48  * APIs.
  49  */
  50 final class EventHandlerProxyCreator {
  51     private static final int CLASS_VERSION = 52;
  52 
  53     private final static Type TYPE_EVENT_TYPE = Type.getType(EventType.class);
  54     private final static Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class);
  55     private final static String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V";
  56     private final static Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("<init>", DESCRIPTOR_EVENT_HANDLER);
  57     private final static String DESCRIPTOR_TIME_STAMP = "()" + Type.LONG_TYPE.getDescriptor();
  58     private final static Method METHOD_TIME_STAMP = new Method("timestamp", DESCRIPTOR_TIME_STAMP);
  59     private final static String DESCRIPTOR_DURATION = "(" + Type.LONG_TYPE.getDescriptor() + ")" + Type.LONG_TYPE.getDescriptor();
  60     private final static Method METHOD_DURATION = new Method("duration", DESCRIPTOR_DURATION);
  61 
  62     private final static ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
  63     private final static String className = "jdk.jfr.proxy.internal.EventHandlerProxy";
  64     private final static String internalClassName = ASMToolkit.getInternalName(className);
  65 
  66     // Create the Proxy class instance after all the previous static fields were initialized (textual order)
  67     static final Class<? extends EventHandler> proxyClass = EventHandlerProxyCreator.makeEventHandlerProxyClass();
  68 
  69     static void ensureInitialized() {
  70         // trigger clinit which will setup the EventHandlerProxy class.
  71     }
  72 
  73     public static Class<? extends EventHandler> makeEventHandlerProxyClass() {
  74         buildClassInfo();
  75         buildConstructor();
  76         buildTimestampMethod();
  77         buildDurationMethod();
  78         byte[] bytes = classWriter.toByteArray();
  79         ASMToolkit.logASM(className, bytes);
  80         return SecuritySupport.defineClass(className, bytes, Event.class.getClassLoader()).asSubclass(EventHandler.class);
  81     }
  82 
  83     private static void buildConstructor() {
  84         MethodVisitor mv = classWriter.visitMethod(0x0, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(), null, null);
  85         mv.visitVarInsn(Opcodes.ALOAD, 0); // this
  86         mv.visitVarInsn(Opcodes.ILOAD, 1); // registered
  87         mv.visitVarInsn(Opcodes.ALOAD, 2); // event type
  88         mv.visitVarInsn(Opcodes.ALOAD, 3); // event control
  89         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(EventHandler.class), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false);
  90         mv.visitInsn(Opcodes.RETURN);
  91         mv.visitMaxs(0, 0);
  92         mv.visitEnd();
  93     }
  94 
  95     private static void buildClassInfo() {
  96         String internalSuperName = ASMToolkit.getInternalName(EventHandler.class.getName());
  97         classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
  98     }
  99 
 100     private static void buildTimestampMethod() {
 101         MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), null, null);
 102         mv.visitCode();
 103         mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
 104         mv.visitInsn(Opcodes.LRETURN);
 105         mv.visitMaxs(0, 0);
 106         mv.visitEnd();
 107     }
 108 
 109     private static void buildDurationMethod() {
 110         MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), null, null);
 111         mv.visitCode();
 112         mv.visitVarInsn(Opcodes.LLOAD, 0);
 113         mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), false);
 114         mv.visitInsn(Opcodes.LRETURN);
 115         mv.visitMaxs(0, 0);
 116         mv.visitEnd();
 117     }
 118 
 119     private static String makeConstructorDescriptor() {
 120         StringJoiner constructordescriptor = new StringJoiner("", "(", ")V");
 121         constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor());
 122         constructordescriptor.add(Type.getType(EventType.class).getDescriptor());
 123         constructordescriptor.add(Type.getType(EventControl.class).getDescriptor());
 124         return constructordescriptor.toString();
 125     }
 126 }