1 #include <assert.h>
2 #include <dlfcn.h>
3 #include <jvmti.h>
4 #include <jni.h>
5 #include <stdint.h>
6 #ifdef __APPLE__
7 #include <pthread.h>
8 #endif
9 
10 
11 #ifndef GLOBALS_H
12 #define GLOBALS_H
13 
14 #define AGENTEXPORT __attribute__((visibility("default"))) JNIEXPORT
15 
16 // Gets us around -Wunused-parameter
17 #define IMPLICITLY_USE(x) (void) x;
18 
19 // Wrap JVMTI functions in this in functions that expect a return
20 // value and require cleanup.
21 #define JVMTI_ERROR_CLEANUP_1(error, retval, cleanup)    \
22   {                                                      \
23     int err;                                             \
24     if ((err = (error)) != JVMTI_ERROR_NONE) {           \
25       fprintf(stderr, "JVMTI error %d\n", err);          \
26       cleanup;                                           \
27       return (retval);                                   \
28     }                                                    \
29   }
30 
31 // Wrap JVMTI functions in this in functions that expect a return value.
32 #define JVMTI_ERROR_1(error, retval) \
33   JVMTI_ERROR_CLEANUP_1(error, retval, /* nothing */)
34 
35 // Wrap JVMTI functions in this in void functions.
36 #define JVMTI_ERROR(error) JVMTI_ERROR_CLEANUP(error, /* nothing */)
37 
38 // Wrap JVMTI functions in this in void functions that require cleanup.
39 #define JVMTI_ERROR_CLEANUP(error, cleanup)      \
40   {                                              \
41     int err;                                     \
42     if ((err = (error)) != JVMTI_ERROR_NONE) {   \
43       fprintf(stderr, "JVMTI error %d\n", err);  \
44       cleanup;                                   \
45       return;                                    \
46     }                                            \
47   }
48 
49 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
50   TypeName(const TypeName&);               \
51   void operator=(const TypeName&)
52 
53 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
54   TypeName();                                    \
55   DISALLOW_COPY_AND_ASSIGN(TypeName)
56 
57 // Short version: reinterpret_cast produces undefined behavior in many
58 // cases where memcpy doesn't.
59 template <class Dest, class Source>
bit_cast(const Source & source)60 inline Dest bit_cast(const Source& source) {
61   // Compile time assertion: sizeof(Dest) == sizeof(Source)
62   // A compile error here means your Dest and Source have different sizes.
63   typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]
64       __attribute__ ((unused));
65 
66   Dest dest;
67   memcpy(&dest, &source, sizeof(dest));
68   return dest;
69 }
70 
71 template<class T>
72 class JvmtiScopedPtr {
73  public:
JvmtiScopedPtr(jvmtiEnv * jvmti)74   explicit JvmtiScopedPtr(jvmtiEnv *jvmti)
75       : jvmti_(jvmti),
76         ref_(NULL) {}
77 
JvmtiScopedPtr(jvmtiEnv * jvmti,T * ref)78   JvmtiScopedPtr(jvmtiEnv *jvmti, T *ref)
79       : jvmti_(jvmti),
80         ref_(ref) {}
81 
~JvmtiScopedPtr()82   ~JvmtiScopedPtr() {
83     if (NULL != ref_) {
84       JVMTI_ERROR(jvmti_->Deallocate((unsigned char *)ref_));
85     }
86   }
87 
GetRef()88   T **GetRef() {
89     assert(ref_ == NULL);
90     return &ref_;
91   }
92 
Get()93   T *Get() {
94     return ref_;
95   }
96 
AbandonBecauseOfError()97   void AbandonBecauseOfError() {
98     ref_ = NULL;
99   }
100 
101  private:
102   jvmtiEnv *jvmti_;
103   T *ref_;
104 
105   DISALLOW_IMPLICIT_CONSTRUCTORS(JvmtiScopedPtr);
106 };
107 
108 // Accessors for a JNIEnv for this thread.
109 class Accessors {
110  public:
111 #ifdef __APPLE__
112   // As of 8/2013, Darwin doesn't support __thread.  We love you,
113   // Darwin!
SetCurrentJniEnv(JNIEnv * env)114   static void SetCurrentJniEnv(JNIEnv *env) {
115     static bool once = false;
116     int err;
117     if ((err = pthread_setspecific(key_, reinterpret_cast<void *>(env))) != 0 &&
118 	!once) {
119       once = true;
120       perror("Was not able to set JNIEnv for at least one thread: ");
121     }
122   }
123 
CurrentJniEnv()124   static JNIEnv *CurrentJniEnv() {
125     JNIEnv *p = reinterpret_cast<JNIEnv *>(pthread_getspecific(key_));
126     return p;
127   }
128 
Init()129   static void Init() {
130     if (pthread_key_create(&key_, NULL) != 0) {
131       perror("Unable to init thread-local storage.  Profiling won't work:");
132     }
133   }
134 
Destroy()135   static void Destroy() {
136     if (pthread_key_delete(key_) != 0) {
137       // Meh.
138     }
139   }
140 #else
141   static void SetCurrentJniEnv(JNIEnv *env) {
142     env_ = env;
143   }
144 
145   static JNIEnv *CurrentJniEnv() {
146     return env_;
147   }
148 
149   static void Init() {
150   }
151 
152   static void Destroy() {
153   }
154 #endif
155 
156   template <class FunctionType>
GetJvmFunction(const char * function_name)157   static inline FunctionType GetJvmFunction(const char *function_name) {
158     // get handle to library
159     static void *handle = dlopen("libjvm.so", RTLD_LAZY);
160     if (handle == NULL) {
161       return NULL;
162     }
163 
164     // get address of function, return null if not found
165     return bit_cast<FunctionType>(dlsym(handle, function_name));
166   }
167 
168  private:
169 #ifdef __APPLE__
170   static pthread_key_t key_;
171 #else
172   // This is very dangerous.  __thread is not async-safe when used in
173   // a shared library, because it calls malloc the first time a given
174   // thread accesses it.  This is unlikely to cause problems in
175   // straightforward Java apps, but a real fix involves either a fix
176   // to glibc or to the Java launcher, and casual users will have a
177     // hard time with this.
178   static __thread JNIEnv *env_;
179 #endif
180 };
181 
182 #if defined(__x86_64__)
183 #define __CAS_INSTR "lock; cmpxchgq %1,%2"
184 #define __ADD_INSTR "lock; xaddq %0,%1"
185 #else
186 #define __CAS_INSTR "lock; cmpxchgl %1,%2"
187 #define __ADD_INSTR "lock; xaddl %0,%1"
188 #endif
189 
NoBarrier_CompareAndSwap(volatile intptr_t * ptr,intptr_t old_value,intptr_t new_value)190 inline intptr_t NoBarrier_CompareAndSwap(volatile intptr_t *ptr,
191                                          intptr_t old_value,
192                                          intptr_t new_value) {
193   intptr_t prev;
194   __asm__ __volatile__(__CAS_INSTR
195                        : "=a"(prev)
196                        : "q"(new_value), "m"(*ptr), "0"(old_value)
197                        : "cc", "memory");
198   return prev;
199 }
200 
NoBarrier_AtomicIncrement(volatile intptr_t * ptr,intptr_t increment)201 inline intptr_t NoBarrier_AtomicIncrement(volatile intptr_t* ptr,
202                                           intptr_t increment) {
203   intptr_t temp = increment;
204   __asm__ __volatile__(__ADD_INSTR
205                        : "+r" (temp), "+m" (*ptr)
206                        : : "cc", "memory");
207   // temp now contains the previous value of *ptr
208   return temp + increment;
209 }
210 
211 #undef __CAS_INSTR
212 #undef __ADD_INSTR
213 
214 // Things that should probably be user-configurable
215 
216 // Number of times per second that we profile
217 static const int kNumInterrupts = 100;
218 
219 // Maximum number of stack traces
220 static const int kMaxStackTraces = 3000;
221 
222 // Maximum number of frames to store from the stack traces sampled.
223 static const int kMaxFramesToCapture = 128;
224 
225 // Location where the data are dumped.
226 static const char kDefaultOutFile[] = "traces.txt";
227 
228 class Globals {
229  public:
230   static FILE *OutFile;
231 };
232 
233 #endif  // GLOBALS_H
234