/* * Copyright (c) 2008, 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. 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 sun.tracing.dtrace; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.annotation.Annotation; import java.util.HashMap; import sun.tracing.ProviderSkeleton; import sun.tracing.ProbeSkeleton; import com.sun.tracing.Provider; import com.sun.tracing.ProviderName; import com.sun.tracing.ProbeName; import com.sun.tracing.dtrace.Attributes; import com.sun.tracing.dtrace.ModuleName; import com.sun.tracing.dtrace.FunctionName; import com.sun.tracing.dtrace.StabilityLevel; import com.sun.tracing.dtrace.DependencyClass; import sun.misc.ProxyGenerator; class DTraceProvider extends ProviderSkeleton { private Activation activation; private Object proxy; // For proxy generation private final static Class[] constructorParams = { InvocationHandler.class }; private final String proxyClassNamePrefix = "$DTraceTracingProxy"; static final String DEFAULT_MODULE = "java_tracing"; static final String DEFAULT_FUNCTION = "unspecified"; private static long nextUniqueNumber = 0; private static synchronized long getUniqueNumber() { return nextUniqueNumber++; } protected ProbeSkeleton createProbe(Method m) { return new DTraceProbe(proxy, m); } DTraceProvider(Class type) { super(type); } void setProxy(Object p) { proxy = p; } void setActivation(Activation a) { this.activation = a; } public void dispose() { if (activation != null) { activation.disposeProvider(this); activation = null; } super.dispose(); } /** * Magic routine which creates an implementation of the user's interface. * * This method uses the ProxyGenerator directly to bypass the * java.lang.reflect.proxy cache so that we get a unique class each * time it's called and can't accidently reuse a $Proxy class. * * @return an implementation of the user's interface */ @SuppressWarnings("unchecked") public T newProxyInstance() { /* * Choose a name for the proxy class to generate. */ long num = getUniqueNumber(); String proxyPkg = ""; if (!Modifier.isPublic(providerType.getModifiers())) { String name = providerType.getName(); int n = name.lastIndexOf('.'); proxyPkg = ((n == -1) ? "" : name.substring(0, n + 1)); } String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ Class proxyClass = null; byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, new Class[] { providerType }); try { proxyClass = JVM.defineClass( providerType.getClassLoader(), proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } /* * Invoke its constructor with the designated invocation handler. */ try { Constructor cons = proxyClass.getConstructor(constructorParams); return (T)cons.newInstance(new Object[] { this }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } } // In the normal case, the proxy object's method implementations will call // this method (it usually calls the ProviderSkeleton's version). That // method uses the passed 'method' object to lookup the associated // 'ProbeSkeleton' and calls uncheckedTrigger() on that probe to cause the // probe to fire. DTrace probes are different in that the proxy class's // methods are immediately overridden with native code to fire the probe // directly. So this method should never get invoked. We also wire up the // DTraceProbe.uncheckedTrigger() method to call the proxy method instead // of doing the work itself. protected void triggerProbe(Method method, Object[] args) { assert false : "This method should have been overridden by the JVM"; } public String getProviderName() { return super.getProviderName(); } String getModuleName() { return getAnnotationString( providerType, ModuleName.class, DEFAULT_MODULE); } static String getProbeName(Method method) { return getAnnotationString( method, ProbeName.class, method.getName()); } static String getFunctionName(Method method) { return getAnnotationString( method, FunctionName.class, DEFAULT_FUNCTION); } DTraceProbe[] getProbes() { return probes.values().toArray(new DTraceProbe[0]); } StabilityLevel getNameStabilityFor(Class type) { Attributes attrs = (Attributes)getAnnotationValue( providerType, type, "value", null); if (attrs == null) { return StabilityLevel.PRIVATE; } else { return attrs.name(); } } StabilityLevel getDataStabilityFor(Class type) { Attributes attrs = (Attributes)getAnnotationValue( providerType, type, "value", null); if (attrs == null) { return StabilityLevel.PRIVATE; } else { return attrs.data(); } } DependencyClass getDependencyClassFor(Class type) { Attributes attrs = (Attributes)getAnnotationValue( providerType, type, "value", null); if (attrs == null) { return DependencyClass.UNKNOWN; } else { return attrs.dependency(); } } }