< prev index next >

core/org.openjdk.jmc.agent/src/main/java/org/openjdk/jmc/agent/util/TypeUtils.java

Print this page




  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  * 
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  * 
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.agent.util;
  34 
  35 import java.lang.reflect.Array;
  36 import java.lang.reflect.Field;



  37 import java.util.List;
  38 import java.util.logging.Level;
  39 import java.util.logging.Logger;
  40 
  41 import org.openjdk.jmc.agent.Parameter;
  42 import org.openjdk.jmc.agent.jfr.impl.JFRUtils;
  43 import org.objectweb.asm.MethodVisitor;
  44 import org.objectweb.asm.Opcodes;
  45 import org.objectweb.asm.Type;
  46 
  47 import sun.misc.Unsafe;

  48 
  49 /**
  50  * Helper methods for doing transforms.
  51  */
  52 public final class TypeUtils {
  53         private static final String NULL_REFERENCE_STRING = "null"; //$NON-NLS-1$
  54         /**
  55          * The internal name of this class.
  56          */
  57         public static final String INAME = Type.getInternalName(TypeUtils.class);
  58         public static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); //$NON-NLS-1$
  59         public static final Type OBJECT_ARRAY_TYPE = Type.getObjectType("[Ljava/lang/Object;"); //$NON-NLS-1$
  60         public static final Type STRING_TYPE = Type.getType("Ljava/lang/String;"); //$NON-NLS-1$
  61 
  62         public static final Object STRING_INTERNAL_NAME = "java/lang/String"; //$NON-NLS-1$
  63 











  64         /**
  65          * The file extension for java source files (.java).
  66          */
  67         public static final String JAVA_FILE_EXTENSION = ".java"; //$NON-NLS-1$
  68 
  69         private TypeUtils() {
  70                 throw new UnsupportedOperationException("Toolkit!"); //$NON-NLS-1$
  71         }
  72 
  73         public static Object box(byte val) {
  74                 return val;
  75         }
  76 
  77         public static Object box(short val) {
  78                 return val;
  79         }
  80 
  81         public static Object box(char val) {
  82                 return val;
  83         }


  91         }
  92 
  93         public static Object box(float val) {
  94                 return val;
  95         }
  96 
  97         public static Object box(double val) {
  98                 return val;
  99         }
 100 
 101         public static String toString(Object o) {
 102                 if (o == null) {
 103                         return NULL_REFERENCE_STRING;
 104                 }
 105                 if (o.getClass().isArray()) {
 106                         return toString(o, Array.getLength(o));
 107                 }
 108                 return String.valueOf(o);
 109         }
 110 
 111         /**
 112          * Type agnostic array toString() which also handles primitive arrays.
 113          */
 114         private static String toString(Object o, int length) {
 115                 int iMax = length - 1;
 116                 if (iMax == -1) {
 117                         return "[]"; //$NON-NLS-1$
 118                 }
 119 
 120                 StringBuilder b = new StringBuilder();
 121                 b.append('[');
 122                 for (int i = 0;; i++) {
 123                         b.append(Array.get(o, i));
 124                         if (i == iMax) {
 125                                 return b.append(']').toString();
 126                         }
 127                         b.append(", "); //$NON-NLS-1$
 128                 }

 129         }
 130 
 131         /**
 132          * Ensure that the operand is on the stack before calling. If type is void, this is a noop, and
 133          * depending on your use case you may instead want to push Opcodes.ACONST_NULL.

 134          */
 135         public static void visitBox(MethodVisitor mv, Type type) {
 136                 switch (type.getSort()) {
 137                 case Type.VOID:
 138                         break;
 139                 case Type.BOOLEAN:
 140                         emitBox(mv, "(Z)Ljava/lang/Object;"); //$NON-NLS-1$
 141                         break;
 142                 case Type.BYTE:
 143                         emitBox(mv, "(B)Ljava/lang/Object;"); //$NON-NLS-1$
 144                         break;
 145                 case Type.CHAR:
 146                         emitBox(mv, "(C)Ljava/lang/Object;"); //$NON-NLS-1$
 147                         break;
 148                 case Type.SHORT:
 149                         emitBox(mv, "(S)Ljava/lang/Object;"); //$NON-NLS-1$
 150                         break;
 151                 case Type.INT:
 152                         emitBox(mv, "(I)Ljava/lang/Object;"); //$NON-NLS-1$
 153                         break;
 154                 case Type.LONG:
 155                         emitBox(mv, "(J)Ljava/lang/Object;"); //$NON-NLS-1$
 156                         break;
 157                 case Type.FLOAT:
 158                         emitBox(mv, "(F)Ljava/lang/Object;"); //$NON-NLS-1$
 159                         break;
 160                 case Type.DOUBLE:
 161                         emitBox(mv, "(D)Ljava/lang/Object;"); //$NON-NLS-1$
 162                         break;
 163                 }
 164         }
 165 
 166         private static void emitBox(MethodVisitor mv, String desc) {
 167                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, INAME, "box", desc, false); //$NON-NLS-1$
 168         }
 169 
 170         public static boolean isValidJavaIdentifier(String identifier) {
 171                 if (identifier == null || identifier.length() == 0) {
 172                         return false;
 173                 }
 174 
 175                 if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
 176                         return false;
 177                 }
 178 
 179                 for (int i = 1; i < identifier.length(); i++) {
 180                         if (!Character.isJavaIdentifierPart(identifier.charAt(i))) {
 181                                 return false;
 182                         }
 183                 }
 184                 return true;
 185         }
 186 
 187         public static String deriveIdentifierPart(String str) {
 188                 StringBuilder builder = new StringBuilder();
 189 


 196                 builder.setCharAt(0, Character.toUpperCase(builder.toString().charAt(0)));
 197                 return builder.toString();
 198         }
 199 
 200         public static String getPathPart(String fqcn) {
 201                 int lastSlashIndex = fqcn.lastIndexOf('/');
 202                 if (lastSlashIndex >= 0) {
 203                         return fqcn.substring(0, lastSlashIndex + 1);
 204                 }
 205                 return fqcn;
 206         }
 207 
 208         public static String getNamePart(String fqcn) {
 209                 int lastSlashIndex = fqcn.lastIndexOf('/');
 210                 if (lastSlashIndex >= 0) {
 211                         return fqcn.substring(lastSlashIndex + 1);
 212                 }
 213                 return fqcn;
 214         }
 215 
 216         public static Unsafe getUnsafe() {
 217                 // Lovely, but this seems to be the only way
 218                 try {
 219                         Field f = Unsafe.class.getDeclaredField("theUnsafe"); //$NON-NLS-1$
 220                         f.setAccessible(true);
 221                         return (Unsafe) f.get(null);
 222                 } catch (Exception e) {
 223                         Logger.getLogger(JFRUtils.class.getName()).log(Level.SEVERE, "Could not access Unsafe!", e); //$NON-NLS-1$
 224                 }
 225                 return null;
 226         }
 227 
 228         public static void stringify(MethodVisitor mv, Parameter param, Type argumentType) {
 229                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, INAME, "toString", //$NON-NLS-1$
 230                                 "(Ljava/lang/Object;)Ljava/lang/String;", false); //$NON-NLS-1$
 231         }
 232 
 233         public static boolean shouldStringify(Parameter param, Type argumentType) {
 234                 if (argumentType.getSort() == Type.ARRAY || argumentType.getSort() == Type.OBJECT) {
 235                         return !argumentType.getInternalName().equals(STRING_INTERNAL_NAME);
 236                 }
 237                 return false;
 238         }
 239 
 240         public static Parameter findReturnParam(List<Parameter> parameters) {
 241                 for (Parameter p : parameters) {
 242                         if (p.isReturn()) {
 243                                 return p;
 244                         }
 245                 }
 246                 return null;
 247         }
 248 
 249         /**
 250          * Transforms a FQN in internal form, so that it can be used in e.g. formal descriptors.

 251          *
 252          * @param className
 253          *            the fully qualified class name in internal form.
 254          * @return the transformed class name.
 255          */
 256         public static String parameterize(String className) {
 257                 return "L" + className + ";"; //$NON-NLS-1$ //$NON-NLS-2$





































































 258         }
 259 }


  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  * 
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  * 
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.agent.util;
  34 
  35 import java.lang.reflect.Array;
  36 import java.lang.reflect.Field;
  37 import java.lang.reflect.InvocationTargetException;
  38 import java.lang.reflect.Method;
  39 import java.security.ProtectionDomain;
  40 import java.util.List;
  41 import java.util.logging.Level;
  42 import java.util.logging.Logger;
  43 


  44 import org.objectweb.asm.MethodVisitor;
  45 import org.objectweb.asm.Opcodes;
  46 import org.objectweb.asm.Type;
  47 import org.openjdk.jmc.agent.Agent;
  48 import org.openjdk.jmc.agent.Parameter;
  49 import org.openjdk.jmc.agent.jfr.impl.JFRUtils;
  50 
  51 /**
  52  * Helper methods for doing transforms.
  53  */
  54 public final class TypeUtils {
  55         private static final String NULL_REFERENCE_STRING = "null"; //$NON-NLS-1$
  56         /**
  57          * The internal name of this class.
  58          */
  59         public static final String INAME = Type.getInternalName(TypeUtils.class);
  60         public static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); //$NON-NLS-1$
  61         public static final Type OBJECT_ARRAY_TYPE = Type.getObjectType("[Ljava/lang/Object;"); //$NON-NLS-1$
  62         public static final Type STRING_TYPE = Type.getType("Ljava/lang/String;"); //$NON-NLS-1$
  63 
  64         public static final Object STRING_INTERNAL_NAME = "java/lang/String"; //$NON-NLS-1$
  65 
  66         private final static String UNSAFE_JDK_7_CLASS = "sun.misc.Unsafe"; //$NON-NLS-1$
  67         private final static String UNSAFE_JDK_11_CLASS = "jdk.internal.misc.Unsafe"; //$NON-NLS-1$
  68 
  69         private static final Object UNSAFE;
  70         private static final Method UNSAFE_DEFINE_CLASS_METHOD;
  71 
  72         static {
  73                 UNSAFE = getUnsafe();
  74                 UNSAFE_DEFINE_CLASS_METHOD = getUnsafeDefineClassMethod(UNSAFE);
  75         }
  76 
  77         /**
  78          * The file extension for java source files (.java).
  79          */
  80         public static final String JAVA_FILE_EXTENSION = ".java"; //$NON-NLS-1$
  81 
  82         private TypeUtils() {
  83                 throw new UnsupportedOperationException("Toolkit!"); //$NON-NLS-1$
  84         }
  85 
  86         public static Object box(byte val) {
  87                 return val;
  88         }
  89 
  90         public static Object box(short val) {
  91                 return val;
  92         }
  93 
  94         public static Object box(char val) {
  95                 return val;
  96         }


 104         }
 105 
 106         public static Object box(float val) {
 107                 return val;
 108         }
 109 
 110         public static Object box(double val) {
 111                 return val;
 112         }
 113 
 114         public static String toString(Object o) {
 115                 if (o == null) {
 116                         return NULL_REFERENCE_STRING;
 117                 }
 118                 if (o.getClass().isArray()) {
 119                         return toString(o, Array.getLength(o));
 120                 }
 121                 return String.valueOf(o);
 122         }
 123 
 124         public static Class<?> defineClass(String eventClassName, byte[] eventClass, int i, int length,
 125                         ClassLoader definingClassLoader, ProtectionDomain protectionDomain) {
 126                 try {
 127                         return (Class<?>) UNSAFE_DEFINE_CLASS_METHOD.invoke(UNSAFE, eventClassName, eventClass, i, length,
 128                                         definingClassLoader, protectionDomain);
 129                 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
 130                         Agent.getLogger().log(Level.SEVERE, "Failed to dynamically define the class " + eventClassName, e); //$NON-NLS-1$










 131                 }
 132                 return null;
 133         }
 134 
 135         /**
 136          * Ensure that the operand is on the stack before calling. If type is void, this
 137          * is a noop, and depending on your use case you may instead want to push
 138          * Opcodes.ACONST_NULL.
 139          */
 140         public static void visitBox(MethodVisitor mv, Type type) {
 141                 switch (type.getSort()) {
 142                 case Type.VOID:
 143                         break;
 144                 case Type.BOOLEAN:
 145                         emitBox(mv, "(Z)Ljava/lang/Object;"); //$NON-NLS-1$
 146                         break;
 147                 case Type.BYTE:
 148                         emitBox(mv, "(B)Ljava/lang/Object;"); //$NON-NLS-1$
 149                         break;
 150                 case Type.CHAR:
 151                         emitBox(mv, "(C)Ljava/lang/Object;"); //$NON-NLS-1$
 152                         break;
 153                 case Type.SHORT:
 154                         emitBox(mv, "(S)Ljava/lang/Object;"); //$NON-NLS-1$
 155                         break;
 156                 case Type.INT:
 157                         emitBox(mv, "(I)Ljava/lang/Object;"); //$NON-NLS-1$
 158                         break;
 159                 case Type.LONG:
 160                         emitBox(mv, "(J)Ljava/lang/Object;"); //$NON-NLS-1$
 161                         break;
 162                 case Type.FLOAT:
 163                         emitBox(mv, "(F)Ljava/lang/Object;"); //$NON-NLS-1$
 164                         break;
 165                 case Type.DOUBLE:
 166                         emitBox(mv, "(D)Ljava/lang/Object;"); //$NON-NLS-1$
 167                         break;
 168                 }
 169         }
 170 




 171         public static boolean isValidJavaIdentifier(String identifier) {
 172                 if (identifier == null || identifier.length() == 0) {
 173                         return false;
 174                 }
 175 
 176                 if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
 177                         return false;
 178                 }
 179 
 180                 for (int i = 1; i < identifier.length(); i++) {
 181                         if (!Character.isJavaIdentifierPart(identifier.charAt(i))) {
 182                                 return false;
 183                         }
 184                 }
 185                 return true;
 186         }
 187 
 188         public static String deriveIdentifierPart(String str) {
 189                 StringBuilder builder = new StringBuilder();
 190 


 197                 builder.setCharAt(0, Character.toUpperCase(builder.toString().charAt(0)));
 198                 return builder.toString();
 199         }
 200 
 201         public static String getPathPart(String fqcn) {
 202                 int lastSlashIndex = fqcn.lastIndexOf('/');
 203                 if (lastSlashIndex >= 0) {
 204                         return fqcn.substring(0, lastSlashIndex + 1);
 205                 }
 206                 return fqcn;
 207         }
 208 
 209         public static String getNamePart(String fqcn) {
 210                 int lastSlashIndex = fqcn.lastIndexOf('/');
 211                 if (lastSlashIndex >= 0) {
 212                         return fqcn.substring(lastSlashIndex + 1);
 213                 }
 214                 return fqcn;
 215         }
 216 












 217         public static void stringify(MethodVisitor mv, Parameter param, Type argumentType) {
 218                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, INAME, "toString", //$NON-NLS-1$
 219                                 "(Ljava/lang/Object;)Ljava/lang/String;", false); //$NON-NLS-1$
 220         }
 221 
 222         public static boolean shouldStringify(Parameter param, Type argumentType) {
 223                 if (argumentType.getSort() == Type.ARRAY || argumentType.getSort() == Type.OBJECT) {
 224                         return !argumentType.getInternalName().equals(STRING_INTERNAL_NAME);
 225                 }
 226                 return false;
 227         }
 228 
 229         public static Parameter findReturnParam(List<Parameter> parameters) {
 230                 for (Parameter p : parameters) {
 231                         if (p.isReturn()) {
 232                                 return p;
 233                         }
 234                 }
 235                 return null;
 236         }
 237 
 238         /**
 239          * Transforms a FQN in internal form, so that it can be used in e.g. formal
 240          * descriptors.
 241          *
 242          * @param className the fully qualified class name in internal form.

 243          * @return the transformed class name.
 244          */
 245         public static String parameterize(String className) {
 246                 return "L" + className + ";"; //$NON-NLS-1$ //$NON-NLS-2$
 247         }
 248 
 249         /**
 250          * Type agnostic array toString() which also handles primitive arrays.
 251          */
 252         private static String toString(Object o, int length) {
 253                 int iMax = length - 1;
 254                 if (iMax == -1) {
 255                         return "[]"; //$NON-NLS-1$
 256                 }
 257 
 258                 StringBuilder b = new StringBuilder();
 259                 b.append('[');
 260                 for (int i = 0;; i++) {
 261                         b.append(Array.get(o, i));
 262                         if (i == iMax) {
 263                                 return b.append(']').toString();
 264                         }
 265                         b.append(", "); //$NON-NLS-1$
 266                 }
 267         }
 268 
 269         private static void emitBox(MethodVisitor mv, String desc) {
 270                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, INAME, "box", desc, false); //$NON-NLS-1$
 271         }
 272 
 273         private static Object getUnsafe() {
 274                 // Lovely, but this seems to be the only way
 275                 Class<?> unsafeClass = getUnsafeClass();
 276                 try {
 277                         Field f = unsafeClass.getDeclaredField("theUnsafe"); //$NON-NLS-1$
 278                         f.setAccessible(true);
 279                         return f.get(null);
 280                 } catch (Exception e) {
 281                         Logger.getLogger(JFRUtils.class.getName()).log(Level.SEVERE, "Could not access Unsafe!", e); //$NON-NLS-1$
 282                 }
 283                 return null;
 284         }
 285 
 286         private static Method getUnsafeDefineClassMethod(Object unsafe) {
 287                 try {
 288                         return unsafe.getClass().getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class,
 289                                         ClassLoader.class, ProtectionDomain.class);
 290                 } catch (NoSuchMethodException | SecurityException e) {
 291                         System.out.println(
 292                                         "Could not find, or access, any defineClass method. The agent will not work. If on JDK 11, try adding  --add-exports java.base/jdk.internal.misc=ALL-UNNAMED"); //$NON-NLS-1$
 293                         e.printStackTrace();
 294                         System.out.flush();
 295                         System.exit(3);
 296                 }
 297                 return null;
 298         }
 299 
 300         private static Class<?> getUnsafeClass() {
 301                 Class<?> clazz = null;
 302                 try {
 303                         clazz = Class.forName(UNSAFE_JDK_11_CLASS);
 304                 } catch (ClassNotFoundException e) {
 305                         try {
 306                                 clazz = Class.forName(UNSAFE_JDK_7_CLASS);
 307                         } catch (ClassNotFoundException e1) {
 308                                 System.out.println(
 309                                                 "Could not find, or access, any Unsafe class. The agent will not work. If on JDK 11, try adding  --add-exports java.base/jdk.internal.misc=ALL-UNNAMED"); //$NON-NLS-1$
 310                                 e1.printStackTrace();
 311                                 System.out.flush();
 312                                 System.exit(2);
 313                         }
 314                 }
 315                 return clazz;
 316         }
 317 }
< prev index next >