/* * Copyright (c) 2012, 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. * * 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 com.sun.max.vm.ext.jvmti; import static com.sun.max.vm.ext.jvmti.JVMTICapabilities.E.*; import static com.sun.max.vm.ext.jvmti.JVMTIConstants.*; import java.io.*; import java.lang.reflect.*; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.ide.*; import com.sun.max.io.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.hosted.*; import com.sun.max.vm.runtime.*; /** * Handles the checking (e.g. capabilities) for agent adapters. The idiom is to subclass this class and call {@code super.method(...)}. * Those methods that require a specific capability (as denoted by the {@link JJVMTI_FUNCTION} annotation in {@link JJVMTI} * have the check generated automatically in this code. Those that don't, have a null implementation that will be inlined * away in the boot image code. */ public class JJVMTIAgentAdapterChecker implements JJVMTI { static { JavaPrototype.registerGeneratedCodeCheckerCallback(new GeneratedCodeCheckerCallback()); } @HOSTED_ONLY private static class GeneratedCodeCheckerCallback implements JavaPrototype.GeneratedCodeCheckerCallback { public void checkGeneratedCode() { boolean updated = checkGeneratedCode(true); if (updated) { FatalError.unexpected("JJVMTIAgentAdapterChecker is out of sync with JJVMTI, regenerate and refresh in IDE"); } } private static class SortableMethod implements Comparable<SortableMethod> { final Method method; SortableMethod(Method method) { this.method = method; } @Override public int compareTo(SortableMethod o) { return method.getName().compareTo(o.method.getName()); } } boolean checkGeneratedCode(boolean checkOnly) { try { File base = new File(JavaProject.findWorkspace(), "com.oracle.max.vm.ext.jvmti" + File.separator + "src"); File outputFile = new File(base, JJVMTIAgentAdapterChecker.class.getName().replace('.', File.separatorChar) + ".java").getAbsoluteFile(); Writer writer = new StringWriter(); PrintWriter out = new PrintWriter(writer); Method[] methods = JJVMTI.class.getDeclaredMethods(); SortableMethod[] sortedMethods = new SortableMethod[methods.length]; for (int i = 0; i < methods.length; i++) { sortedMethods[i] = new SortableMethod(methods[i]); } Arrays.sort(sortedMethods); for (SortableMethod sm : sortedMethods) { Method m = sm.method; Class<?> returnType = m.getReturnType(); out.println(" @Override"); out.printf(" public %s %s(", getTypeName(m.getReturnType(), m.getGenericReturnType()), m.getName()); Class< ? >[] params = m.getParameterTypes(); Type[] genericParams = m.getGenericParameterTypes(); int argIndex = 0; for (Class param : params) { if (argIndex > 0) { out.print(", "); } out.printf("%s arg%d", getTypeName(param, genericParams[argIndex]), argIndex); argIndex++; } out.println(") {"); JJVMTI_FUNCTION capAnnotation = m.getAnnotation(JJVMTI_FUNCTION.class); if (capAnnotation != null) { out.printf(" checkCap(%s);%n", JVMTICapabilities.E.VALUES[capAnnotation.cap().ordinal()]); } if (returnType != void.class) { out.print(" return "); if (returnType == boolean.class) { out.print("false"); } else if (returnType == int.class || returnType == long.class) { out.print("0"); } else if (returnType == float.class) { out.print("0.0F"); } else if (returnType == double.class) { out.print("0.0"); } else { out.print("null"); } out.println(";"); } out.println(" }\n"); } writer.close(); boolean wouldUpdate = Files.updateGeneratedContent(outputFile, ReadableSource.Static.fromString(writer.toString()), "// START GENERATED CODE", "// END GENERATED CODE", checkOnly); return wouldUpdate; } catch (Exception exception) { FatalError.unexpected("Error while generating source for " + JJVMTIAgentAdapterChecker.class.getName(), exception); return false; } } private static String getTypeName(Class<?> returnClass, Type returnType) { if (returnType == returnClass) { return handleE(returnClass, false); } else { ParameterizedType pType = (ParameterizedType) returnType; Type[] pTypeArgs = pType.getActualTypeArguments(); Class<?> pTypeArg0Class = (Class) pTypeArgs[0]; return returnClass.getSimpleName() + "<" + handleE(pTypeArg0Class, true) + ">"; } } private static String handleE(Class<?> klass, boolean parameterized) { String name = klass.getSimpleName(); if (name.equals("E")) { Class decl = klass.getEnclosingClass(); return decl.getSimpleName() + "." + name; } else { return name; } } } @HOSTED_ONLY public static void main(String[] args) { boolean checkOnly = args.length > 0 && args[0].equals("-check"); boolean wouldUpdate = new GeneratedCodeCheckerCallback().checkGeneratedCode(checkOnly); if (wouldUpdate) { System.out.println("JJVMTIAgentAdapterChecker " + (checkOnly ? "would be" : "was") + " updated"); } } protected JVMTI.JavaEnv env; private void checkCap(JVMTICapabilities.E cap) { if (!env.capabilities.contains(cap)) { throw new JJVMTI.JJVMTIException(JVMTI_ERROR_MUST_POSSESS_CAPABILITY); } } // START GENERATED CODE @Override public void addCapabilities(EnumSet<JVMTICapabilities.E> arg0) { } @Override public void addToBootstrapClassLoaderSearch(String arg0) { } @Override public void addToSystemClassLoaderSearch(String arg0) { } @Override public void clearBreakpoint(ClassMethodActor arg0, long arg1) { checkCap(CAN_GENERATE_BREAKPOINT_EVENTS); } @Override public void clearFieldAccessWatch(FieldActor arg0) { checkCap(CAN_GENERATE_FIELD_ACCESS_EVENTS); } @Override public void clearFieldModificationWatch(FieldActor arg0) { checkCap(CAN_GENERATE_FIELD_MODIFICATION_EVENTS); } @Override public void disposeEnvironment() { } @Override public void forceEarlyReturnDouble(Thread arg0, double arg1) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceEarlyReturnFloat(Thread arg0, float arg1) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceEarlyReturnInt(Thread arg0, int arg1) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceEarlyReturnLong(Thread arg0, long arg1) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceEarlyReturnObject(Thread arg0, Object arg1) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceEarlyReturnVoid(Thread arg0) { checkCap(CAN_FORCE_EARLY_RETURN); } @Override public void forceGarbageCollection() { } @Override public StackInfo[] getAllStackTraces(int arg0) { return null; } @Override public Thread[] getAllThreads() { return null; } @Override public int getArgumentsSize(ClassMethodActor arg0) { return 0; } @Override public int getAvailableProcessors() { return 0; } @Override public byte[] getBytecodes(ClassMethodActor arg0) { checkCap(CAN_GET_BYTECODES); return null; } @Override public EnumSet<JVMTICapabilities.E> getCapabilities() { return null; } @Override public FieldActor[] getClassFields(ClassActor arg0) { return null; } @Override public ClassLoader getClassLoader(ClassActor arg0) { return null; } @Override public ClassActor[] getClassLoaderClasses(ClassLoader arg0) { return null; } @Override public MethodActor[] getClassMethods(ClassActor arg0) { return null; } @Override public int getClassModifiers(ClassActor arg0) { return 0; } @Override public String getClassSignature(ClassActor arg0) { return null; } @Override public int getClassStatus(ClassActor arg0) { return 0; } @Override public ClassVersionInfo getClassVersionNumbers(ClassActor arg0) { return null; } @Override public byte[] getConstantPool(ClassActor arg0) { checkCap(CAN_GET_CONSTANT_POOL); return null; } @Override public Object getCurrentContendedMonitor(Thread arg0) { checkCap(CAN_GET_CURRENT_CONTENDED_MONITOR); return null; } @Override public Thread getCurrentThread() { return null; } @Override public long getCurrentThreadCpuTime() { return 0; } @Override public String getErrorName(int arg0) { return null; } @Override public ClassActor getFieldDeclaringClass(FieldActor arg0) { return null; } @Override public int getFieldModifiers(FieldActor arg0) { return 0; } @Override public String getFieldName(FieldActor arg0) { return null; } @Override public String getFieldSignature(FieldActor arg0) { return null; } @Override public int getFrameCount(Thread arg0) { return 0; } @Override public FrameInfo getFrameLocation(Thread arg0, int arg1) { return null; } @Override public ClassActor[] getImplementedInterfaces(ClassActor arg0) { return null; } @Override public int getJLocationFormat() { return 0; } @Override public LineNumberEntry[] getLineNumberTable(ClassMethodActor arg0) { checkCap(CAN_GET_LINE_NUMBERS); return null; } @Override public ClassActor[] getLoadedClasses() { return null; } @Override public double getLocalDouble(Thread arg0, int arg1, int arg2) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return 0.0; } @Override public float getLocalFloat(Thread arg0, int arg1, int arg2) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return 0.0F; } @Override public int getLocalInt(Thread arg0, int arg1, int arg2) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return 0; } @Override public long getLocalLong(Thread arg0, int arg1, int arg2) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return 0; } @Override public Object getLocalObject(Thread arg0, int arg1, int arg2) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return null; } @Override public LocalVariableEntry[] getLocalVariableTable(ClassMethodActor arg0) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); return null; } @Override public int getMaxLocals(ClassMethodActor arg0) { return 0; } @Override public ClassActor getMethodDeclaringClass(MethodActor arg0) { return null; } @Override public String getMethodGenericSignature(MethodActor arg0) { return null; } @Override public MethodLocation getMethodLocation(ClassMethodActor arg0) { return null; } @Override public int getMethodModifiers(MethodActor arg0) { return 0; } @Override public String getMethodName(MethodActor arg0) { return null; } @Override public String getMethodSignature(MethodActor arg0) { return null; } @Override public int getObjectHashCode(Object arg0) { return 0; } @Override public ObjectMonitorUsage getObjectMonitorUsage(Object arg0) { checkCap(CAN_GET_MONITOR_INFO); return null; } @Override public long getObjectSize(Object arg0) { return 0; } @Override public void getOwnedMonitorInfo(Thread arg0) { checkCap(CAN_GET_OWNED_MONITOR_INFO); } @Override public MonitorStackDepthInfo[] getOwnedMonitorStackDepthInfo(Thread arg0) { checkCap(CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO); return null; } @Override public int getPhase() { return 0; } @Override public EnumSet<JVMTICapabilities.E> getPotentialCapabilities() { return null; } @Override public String getSourceDebugExtension(ClassActor arg0) { return null; } @Override public String getSourceFileName(ClassActor arg0) { checkCap(CAN_GET_SOURCE_FILE_NAME); return null; } @Override public FrameInfo[] getStackTrace(Thread arg0, int arg1, int arg2) { return null; } @Override public String[] getSystemProperties() { return null; } @Override public String getSystemProperty(String arg0) { return null; } @Override public Object getTag(Object arg0) { checkCap(CAN_TAG_OBJECTS); return null; } @Override public long getThreadCpuTime(Thread arg0) { return 0; } @Override public ThreadGroupChildrenInfo getThreadGroupChildren(ThreadGroup arg0) { return null; } @Override public ThreadGroupInfo getThreadGroupInfo(ThreadGroup arg0) { return null; } @Override public ThreadInfo getThreadInfo(Thread arg0) { return null; } @Override public StackInfo[] getThreadListStackTraces(Thread[] arg0, int arg1) { return null; } @Override public int getThreadState(Thread arg0) { return 0; } @Override public long getTime() { return 0; } @Override public ThreadGroup[] getTopThreadGroups() { return null; } @Override public int getVersionNumber() { return 0; } @Override public void includeMaxVMClasses(boolean arg0) { } @Override public void interruptThread(Thread arg0) { checkCap(CAN_SIGNAL_THREAD); } @Override public boolean isArrayClass(ClassActor arg0) { return false; } @Override public boolean isFieldSynthetic(FieldActor arg0) { checkCap(CAN_GET_SYNTHETIC_ATTRIBUTE); return false; } @Override public boolean isInterface(ClassActor arg0) { return false; } @Override public boolean isMethodNative(MethodActor arg0) { return false; } @Override public boolean isMethodObsolete(MethodActor arg0) { return false; } @Override public boolean isMethodSynthetic(MethodActor arg0) { checkCap(CAN_GET_SYNTHETIC_ATTRIBUTE); return false; } @Override public boolean isModifiableClass(ClassActor arg0) { return false; } @Override public void iterateThroughHeap(int arg0, ClassActor arg1, HeapCallbacks arg2, Object arg3) { checkCap(CAN_TAG_OBJECTS); } @Override public void iterateThroughHeapMax(int arg0, ClassActor arg1, HeapCallbacks arg2, Object arg3) { } @Override public void notifyFramePop(Thread arg0, int arg1) { checkCap(CAN_GENERATE_FRAME_POP_EVENTS); } @Override public void popFrame(Thread arg0) { checkCap(CAN_POP_FRAME); } @Override public void redefineClasses(ClassDefinition[] arg0) { checkCap(CAN_REDEFINE_CLASSES); } @Override public void relinquishCapabilities(EnumSet<JVMTICapabilities.E> arg0) { } @Override public void resumeThread(Thread arg0) { checkCap(CAN_SUSPEND); } @Override public int[] resumeThreadList(Thread[] arg0) { checkCap(CAN_SUSPEND); return null; } @Override public void retransformClasses(ClassActor[] arg0) { } @Override public void runAgentThread(Thread arg0, int arg1) { } @Override public void setBreakpoint(ClassMethodActor arg0, long arg1) { checkCap(CAN_GENERATE_BREAKPOINT_EVENTS); } @Override public void setEventNotificationMode(int arg0, JVMTIEvents.E arg1, Thread arg2) { } @Override public void setFieldAccessWatch(FieldActor arg0) { checkCap(CAN_GENERATE_FIELD_ACCESS_EVENTS); } @Override public void setFieldModificationWatch(FieldActor arg0) { checkCap(CAN_GENERATE_FIELD_MODIFICATION_EVENTS); } @Override public void setLocalDouble(Thread arg0, int arg1, int arg2, double arg3) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); } @Override public void setLocalFloat(Thread arg0, int arg1, int arg2, float arg3) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); } @Override public void setLocalInt(Thread arg0, int arg1, int arg2, int arg3) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); } @Override public void setLocalLong(Thread arg0, int arg1, int arg2, long arg3) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); } @Override public void setLocalObject(Thread arg0, int arg1, int arg2, Object arg3) { checkCap(CAN_ACCESS_LOCAL_VARIABLES); } @Override public void setNativeMethodPrefix(String arg0) { checkCap(CAN_SET_NATIVE_METHOD_PREFIX); } @Override public void setNativeMethodPrefixes(String[] arg0) { checkCap(CAN_SET_NATIVE_METHOD_PREFIX); } @Override public void setSystemProperty(String arg0, String arg1) { } @Override public void setTag(Object arg0, Object arg1) { checkCap(CAN_TAG_OBJECTS); } @Override public void setVerboseFlag(int arg0, boolean arg1) { } @Override public void stopThread(Thread arg0, Throwable arg1) { checkCap(CAN_SIGNAL_THREAD); } @Override public void suspendThread(Thread arg0) { checkCap(CAN_SUSPEND); } @Override public int[] suspendThreadList(Thread[] arg0) { checkCap(CAN_SUSPEND); return null; } // END GENERATED CODE }