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