1 /*
2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.tracing.dtrace;
27 
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.lang.reflect.Constructor;
31 import java.lang.reflect.InvocationHandler;
32 import java.lang.reflect.InvocationTargetException;
33 import java.lang.annotation.Annotation;
34 
35 import sun.tracing.ProviderSkeleton;
36 import sun.tracing.ProbeSkeleton;
37 import com.sun.tracing.Provider;
38 import com.sun.tracing.ProbeName;
39 import com.sun.tracing.dtrace.Attributes;
40 import com.sun.tracing.dtrace.ModuleName;
41 import com.sun.tracing.dtrace.FunctionName;
42 import com.sun.tracing.dtrace.StabilityLevel;
43 import com.sun.tracing.dtrace.DependencyClass;
44 
45 import sun.misc.ProxyGenerator;
46 
47 class DTraceProvider extends ProviderSkeleton {
48 
49     private Activation activation;
50     private Object proxy;
51 
52     // For proxy generation
53     private final static Class[] constructorParams = { InvocationHandler.class };
54     private final String proxyClassNamePrefix = "$DTraceTracingProxy";
55 
56     static final String DEFAULT_MODULE = "java_tracing";
57     static final String DEFAULT_FUNCTION = "unspecified";
58 
59     private static long nextUniqueNumber = 0;
getUniqueNumber()60     private static synchronized long getUniqueNumber() {
61         return nextUniqueNumber++;
62     }
63 
createProbe(Method m)64     protected ProbeSkeleton createProbe(Method m) {
65         return new DTraceProbe(proxy, m);
66     }
67 
DTraceProvider(Class<? extends Provider> type)68     DTraceProvider(Class<? extends Provider> type) {
69         super(type);
70     }
71 
setProxy(Object p)72     void setProxy(Object p) {
73         proxy = p;
74     }
75 
setActivation(Activation a)76     void setActivation(Activation a) {
77         this.activation = a;
78     }
79 
dispose()80     public void dispose() {
81         if (activation != null) {
82             activation.disposeProvider(this);
83             activation = null;
84         }
85         super.dispose();
86     }
87 
88     /**
89      * Magic routine which creates an implementation of the user's interface.
90      *
91      * This method uses the ProxyGenerator directly to bypass the
92      * java.lang.reflect.proxy cache so that we get a unique class each
93      * time it's called and can't accidently reuse a $Proxy class.
94      *
95      * @return an implementation of the user's interface
96      */
97     @SuppressWarnings("unchecked")
newProxyInstance()98     public <T extends Provider> T newProxyInstance() {
99         /*
100          * Choose a name for the proxy class to generate.
101          */
102         long num = getUniqueNumber();
103 
104         String proxyPkg = "";
105         if (!Modifier.isPublic(providerType.getModifiers())) {
106             String name = providerType.getName();
107             int n = name.lastIndexOf('.');
108             proxyPkg = ((n == -1) ? "" : name.substring(0, n + 1));
109         }
110 
111         String proxyName = proxyPkg + proxyClassNamePrefix + num;
112 
113         /*
114          * Generate the specified proxy class.
115          */
116         Class<?> proxyClass = null;
117         byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
118                 proxyName, new Class<?>[] { providerType });
119         try {
120             proxyClass = JVM.defineClass(
121                 providerType.getClassLoader(), proxyName,
122                 proxyClassFile, 0, proxyClassFile.length);
123         } catch (ClassFormatError e) {
124             /*
125              * A ClassFormatError here means that (barring bugs in the
126              * proxy class generation code) there was some other
127              * invalid aspect of the arguments supplied to the proxy
128              * class creation (such as virtual machine limitations
129              * exceeded).
130              */
131             throw new IllegalArgumentException(e.toString());
132         }
133 
134         /*
135          * Invoke its constructor with the designated invocation handler.
136          */
137         try {
138             Constructor cons = proxyClass.getConstructor(constructorParams);
139             return (T)cons.newInstance(new Object[] { this });
140         } catch (ReflectiveOperationException e) {
141             throw new InternalError(e.toString(), e);
142         }
143     }
144 
145     // In the normal case, the proxy object's method implementations will call
146     // this method (it usually calls the ProviderSkeleton's version).  That
147     // method uses the passed 'method' object to lookup the associated
148     // 'ProbeSkeleton' and calls uncheckedTrigger() on that probe to cause the
149     // probe to fire.  DTrace probes are different in that the proxy class's
150     // methods are immediately overridden with native code to fire the probe
151     // directly.  So this method should never get invoked.  We also wire up the
152     // DTraceProbe.uncheckedTrigger() method to call the proxy method instead
153     // of doing the work itself.
triggerProbe(Method method, Object[] args)154     protected void triggerProbe(Method method, Object[] args) {
155         assert false : "This method should have been overridden by the JVM";
156     }
157 
getProviderName()158     public String getProviderName() {
159         return super.getProviderName();
160     }
161 
getModuleName()162     String getModuleName() {
163         return getAnnotationString(
164             providerType, ModuleName.class, DEFAULT_MODULE);
165     }
166 
getProbeName(Method method)167     static String getProbeName(Method method) {
168         return getAnnotationString(
169             method, ProbeName.class, method.getName());
170     }
171 
getFunctionName(Method method)172     static String getFunctionName(Method method) {
173         return getAnnotationString(
174             method, FunctionName.class, DEFAULT_FUNCTION);
175     }
176 
getProbes()177     DTraceProbe[] getProbes() {
178         return probes.values().toArray(new DTraceProbe[0]);
179     }
180 
getNameStabilityFor(Class<? extends Annotation> type)181     StabilityLevel getNameStabilityFor(Class<? extends Annotation> type) {
182         Attributes attrs = (Attributes)getAnnotationValue(
183             providerType, type, "value", null);
184         if (attrs == null) {
185             return StabilityLevel.PRIVATE;
186         } else {
187             return attrs.name();
188         }
189     }
190 
getDataStabilityFor(Class<? extends Annotation> type)191     StabilityLevel getDataStabilityFor(Class<? extends Annotation> type) {
192         Attributes attrs = (Attributes)getAnnotationValue(
193             providerType, type, "value", null);
194         if (attrs == null) {
195             return StabilityLevel.PRIVATE;
196         } else {
197             return attrs.data();
198         }
199     }
200 
getDependencyClassFor(Class<? extends Annotation> type)201     DependencyClass getDependencyClassFor(Class<? extends Annotation> type) {
202         Attributes attrs = (Attributes)getAnnotationValue(
203             providerType, type, "value", null);
204         if (attrs == null) {
205             return DependencyClass.UNKNOWN;
206         } else {
207             return attrs.dependency();
208         }
209     }
210 }
211