blob: 312bb304777849f8c74fc4d701990ea1eb27d1c2 [file] [log] [blame]
Carl Shapirob5573532011-07-12 18:22:59 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "thread.h"
Carl Shapirob5573532011-07-12 18:22:59 -07004
Ian Rogersb033c752011-07-20 12:22:35 -07005#include <pthread.h>
6#include <sys/mman.h>
Elliott Hughesa0957642011-09-02 14:27:33 -07007
Carl Shapirob5573532011-07-12 18:22:59 -07008#include <algorithm>
Elliott Hughesdcc24742011-09-07 14:02:44 -07009#include <bitset>
Elliott Hugheseb4f6142011-07-15 17:43:51 -070010#include <cerrno>
Elliott Hughesa0957642011-09-02 14:27:33 -070011#include <iostream>
Carl Shapirob5573532011-07-12 18:22:59 -070012#include <list>
Carl Shapirob5573532011-07-12 18:22:59 -070013
Elliott Hughesa5b897e2011-08-16 11:33:06 -070014#include "class_linker.h"
Ian Rogers408f79a2011-08-23 18:22:33 -070015#include "heap.h"
Elliott Hughesc5f7c912011-08-18 14:00:42 -070016#include "jni_internal.h"
Elliott Hughesa5b897e2011-08-16 11:33:06 -070017#include "object.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070018#include "runtime.h"
buzbee54330722011-08-23 16:46:55 -070019#include "runtime_support.h"
Ian Rogersaaa20802011-09-11 21:47:37 -070020#include "scoped_jni_thread_state.h"
Elliott Hughes8daa0922011-09-11 13:46:25 -070021#include "thread_list.h"
Elliott Hughesa0957642011-09-02 14:27:33 -070022#include "utils.h"
Carl Shapirob5573532011-07-12 18:22:59 -070023
24namespace art {
25
26pthread_key_t Thread::pthread_key_self_;
27
buzbee4a3164f2011-09-03 11:25:10 -070028// Temporary debugging hook for compiler.
29static void DebugMe(Method* method, uint32_t info) {
30 LOG(INFO) << "DebugMe";
31 if (method != NULL)
32 LOG(INFO) << PrettyMethod(method);
33 LOG(INFO) << "Info: " << info;
34}
35
36/*
37 * TODO: placeholder for a method that can be called by the
38 * invoke-interface trampoline to unwind and handle exception. The
39 * trampoline will arrange it so that the caller appears to be the
40 * callsite of the failed invoke-interface. See comments in
41 * compiler/runtime_support.S
42 */
43extern "C" void artFailedInvokeInterface()
44{
45 UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
46}
47
48// TODO: placeholder. See comments in compiler/runtime_support.S
49extern "C" uint64_t artFindInterfaceMethodInCache(uint32_t method_idx,
50 Object* this_object , Method* caller_method)
51{
52 /*
53 * Note: this_object has not yet been null-checked. To match
54 * the old-world state, nullcheck this_object and load
55 * Class* this_class = this_object->GetClass().
56 * See comments and possible thrown exceptions in old-world
57 * Interp.cpp:dvmInterpFindInterfaceMethod, and complete with
58 * new-world FindVirtualMethodForInterface.
59 */
60 UNIMPLEMENTED(FATAL) << "Unimplemented invoke interface";
61 return 0LL;
62}
63
buzbee1b4c8592011-08-31 10:43:51 -070064// TODO: placeholder. This is what generated code will call to throw
65static void ThrowException(Thread* thread, Throwable* exception) {
66 /*
67 * exception may be NULL, in which case this routine should
68 * throw NPE. NOTE: this is a convenience for generated code,
69 * which previuosly did the null check inline and constructed
70 * and threw a NPE if NULL. This routine responsible for setting
71 * exception_ in thread.
72 */
73 UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
74}
75
76// TODO: placeholder. Helper function to type
77static Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
78 /*
79 * Should initialize & fix up method->dex_cache_resolved_types_[].
80 * Returns initialized type. Does not return normally if an exception
81 * is thrown, but instead initiates the catch. Should be similar to
82 * ClassLinker::InitializeStaticStorageFromCode.
83 */
84 UNIMPLEMENTED(FATAL);
85 return NULL;
86}
87
buzbee561227c2011-09-02 15:28:19 -070088// TODO: placeholder. Helper function to resolve virtual method
89static void ResolveMethodFromCode(Method* method, uint32_t method_idx) {
90 /*
91 * Slow-path handler on invoke virtual method path in which
92 * base method is unresolved at compile-time. Doesn't need to
93 * return anything - just either ensure that
94 * method->dex_cache_resolved_methods_(method_idx) != NULL or
95 * throw and unwind. The caller will restart call sequence
96 * from the beginning.
97 */
98}
99
buzbee1da522d2011-09-04 11:22:20 -0700100// TODO: placeholder. Helper function to alloc array for OP_FILLED_NEW_ARRAY
101static Array* CheckAndAllocFromCode(uint32_t type_index, Method* method,
102 int32_t component_count)
103{
104 /*
105 * Just a wrapper around Array::AllocFromCode() that additionally
106 * throws a runtime exception "bad Filled array req" for 'D' and 'J'.
107 */
108 UNIMPLEMENTED(WARNING) << "Need check that not 'D' or 'J'";
109 return Array::AllocFromCode(type_index, method, component_count);
110}
111
buzbee2a475e72011-09-07 17:19:17 -0700112// TODO: placeholder (throw on failure)
113static void CheckCastFromCode(const Class* a, const Class* b) {
114 if (a->IsAssignableFrom(b)) {
115 return;
116 }
117 UNIMPLEMENTED(FATAL);
118}
119
120// TODO: placeholder
121static void UnlockObjectFromCode(Thread* thread, Object* obj) {
122 // TODO: throw and unwind if lock not held
123 // TODO: throw and unwind on NPE
buzbee4ef76522011-09-08 10:00:32 -0700124 obj->MonitorExit(thread);
buzbee2a475e72011-09-07 17:19:17 -0700125}
126
127// TODO: placeholder
128static void LockObjectFromCode(Thread* thread, Object* obj) {
buzbee4ef76522011-09-08 10:00:32 -0700129 obj->MonitorEnter(thread);
buzbee2a475e72011-09-07 17:19:17 -0700130}
131
buzbee0d966cf2011-09-08 17:34:58 -0700132// TODO: placeholder
133static void CheckSuspendFromCode(Thread* thread) {
134 /*
135 * Code is at a safe point, suspend if needed.
136 * Also, this is where a pending safepoint callback
137 * would be fired.
138 */
139}
140
buzbeecefd1872011-09-09 09:59:52 -0700141// TODO: placeholder
142static void StackOverflowFromCode(Method* method) {
143 //NOTE: to save code space, this handler needs to look up its own Thread*
144 UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
145}
146
buzbee5ade1d22011-09-09 14:44:52 -0700147// TODO: placeholder
148static void ThrowNullPointerFromCode() {
149 //NOTE: to save code space, this handler must look up caller's Method*
150 UNIMPLEMENTED(FATAL) << "Null pointer exception";
151}
152
153// TODO: placeholder
154static void ThrowDivZeroFromCode() {
155 UNIMPLEMENTED(FATAL) << "Divide by zero";
156}
157
158// TODO: placeholder
159static void ThrowArrayBoundsFromCode(int32_t index, int32_t limit) {
160 UNIMPLEMENTED(FATAL) << "Bound check exception, idx: " << index <<
161 ", limit: " << limit;
162}
163
164// TODO: placeholder
165static void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
166 UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
167 " ref: " << ref;
168}
169
170// TODO: placeholder
171static void ThrowNegArraySizeFromCode(int32_t index) {
172 UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
173}
174
175// TODO: placeholder
176static void ThrowInternalErrorFromCode(int32_t errnum) {
177 UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
178}
179
180// TODO: placeholder
181static void ThrowRuntimeExceptionFromCode(int32_t errnum) {
182 UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
183}
184
185// TODO: placeholder
186static void ThrowNoSuchMethodFromCode(int32_t method_idx) {
187 UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
188}
189
190/*
191 * Temporary placeholder. Should include run-time checks for size
192 * of fill data <= size of array. If not, throw arrayOutOfBoundsException.
193 * As with other new "FromCode" routines, this should return to the caller
194 * only if no exception has been thrown.
195 *
196 * NOTE: When dealing with a raw dex file, the data to be copied uses
197 * little-endian ordering. Require that oat2dex do any required swapping
198 * so this routine can get by with a memcpy().
199 *
200 * Format of the data:
201 * ushort ident = 0x0300 magic value
202 * ushort width width of each element in the table
203 * uint size number of elements in the table
204 * ubyte data[size*width] table of data values (may contain a single-byte
205 * padding at the end)
206 */
207static void HandleFillArrayDataFromCode(Array* array, const uint16_t* table)
208{
209 uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
210 uint32_t size_in_bytes = size * table[1];
211 if (static_cast<int32_t>(size) > array->GetLength()) {
212 ThrowArrayBoundsFromCode(array->GetLength(), size);
213 }
214 memcpy((char*)array + art::Array::DataOffset().Int32Value(),
215 (char*)&table[4], size_in_bytes);
216}
217
218// TODO: move to more appropriate location
219/*
220 * Float/double conversion requires clamping to min and max of integer form. If
221 * target doesn't support this normally, use these.
222 */
223static int64_t D2L(double d)
224{
225 static const double kMaxLong = (double)(int64_t)0x7fffffffffffffffULL;
226 static const double kMinLong = (double)(int64_t)0x8000000000000000ULL;
227 if (d >= kMaxLong)
228 return (int64_t)0x7fffffffffffffffULL;
229 else if (d <= kMinLong)
230 return (int64_t)0x8000000000000000ULL;
231 else if (d != d) // NaN case
232 return 0;
233 else
234 return (int64_t)d;
235}
236
237static int64_t F2L(float f)
238{
239 static const float kMaxLong = (float)(int64_t)0x7fffffffffffffffULL;
240 static const float kMinLong = (float)(int64_t)0x8000000000000000ULL;
241 if (f >= kMaxLong)
242 return (int64_t)0x7fffffffffffffffULL;
243 else if (f <= kMinLong)
244 return (int64_t)0x8000000000000000ULL;
245 else if (f != f) // NaN case
246 return 0;
247 else
248 return (int64_t)f;
249}
250
buzbee3ea4ec52011-08-22 17:37:19 -0700251void Thread::InitFunctionPointers() {
buzbee54330722011-08-23 16:46:55 -0700252#if defined(__arm__)
253 pShlLong = art_shl_long;
254 pShrLong = art_shr_long;
255 pUshrLong = art_ushr_long;
buzbee7b1b86d2011-08-26 18:59:10 -0700256 pIdiv = __aeabi_idiv;
257 pIdivmod = __aeabi_idivmod;
258 pI2f = __aeabi_i2f;
259 pF2iz = __aeabi_f2iz;
260 pD2f = __aeabi_d2f;
261 pF2d = __aeabi_f2d;
262 pD2iz = __aeabi_d2iz;
263 pL2f = __aeabi_l2f;
264 pL2d = __aeabi_l2d;
265 pFadd = __aeabi_fadd;
266 pFsub = __aeabi_fsub;
267 pFdiv = __aeabi_fdiv;
268 pFmul = __aeabi_fmul;
269 pFmodf = fmodf;
270 pDadd = __aeabi_dadd;
271 pDsub = __aeabi_dsub;
272 pDdiv = __aeabi_ddiv;
273 pDmul = __aeabi_dmul;
274 pFmod = fmod;
buzbee7b1b86d2011-08-26 18:59:10 -0700275 pLdivmod = __aeabi_ldivmod;
buzbee439c4fa2011-08-27 15:59:07 -0700276 pLmul = __aeabi_lmul;
buzbee4a3164f2011-09-03 11:25:10 -0700277 pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
buzbee54330722011-08-23 16:46:55 -0700278#endif
buzbeec396efc2011-09-11 09:36:41 -0700279 pF2l = F2L;
280 pD2l = D2L;
buzbeedfd3d702011-08-28 12:56:51 -0700281 pAllocFromCode = Array::AllocFromCode;
buzbee1da522d2011-09-04 11:22:20 -0700282 pCheckAndAllocFromCode = CheckAndAllocFromCode;
Brian Carlstrom1f870082011-08-23 16:02:11 -0700283 pAllocObjectFromCode = Class::AllocObjectFromCode;
buzbee3ea4ec52011-08-22 17:37:19 -0700284 pMemcpy = memcpy;
buzbee1b4c8592011-08-31 10:43:51 -0700285 pHandleFillArrayDataFromCode = HandleFillArrayDataFromCode;
buzbeee1931742011-08-28 21:15:53 -0700286 pGet32Static = Field::Get32StaticFromCode;
287 pSet32Static = Field::Set32StaticFromCode;
288 pGet64Static = Field::Get64StaticFromCode;
289 pSet64Static = Field::Set64StaticFromCode;
290 pGetObjStatic = Field::GetObjStaticFromCode;
291 pSetObjStatic = Field::SetObjStaticFromCode;
buzbee1b4c8592011-08-31 10:43:51 -0700292 pCanPutArrayElementFromCode = Class::CanPutArrayElementFromCode;
293 pThrowException = ThrowException;
294 pInitializeTypeFromCode = InitializeTypeFromCode;
buzbee561227c2011-09-02 15:28:19 -0700295 pResolveMethodFromCode = ResolveMethodFromCode;
buzbee1da522d2011-09-04 11:22:20 -0700296 pInitializeStaticStorage = ClassLinker::InitializeStaticStorageFromCode;
buzbee2a475e72011-09-07 17:19:17 -0700297 pInstanceofNonTrivialFromCode = Object::InstanceOf;
298 pCheckCastFromCode = CheckCastFromCode;
299 pLockObjectFromCode = LockObjectFromCode;
300 pUnlockObjectFromCode = UnlockObjectFromCode;
buzbee34cd9e52011-09-08 14:31:52 -0700301 pFindFieldFromCode = Field::FindFieldFromCode;
buzbee0d966cf2011-09-08 17:34:58 -0700302 pCheckSuspendFromCode = CheckSuspendFromCode;
buzbeecefd1872011-09-09 09:59:52 -0700303 pStackOverflowFromCode = StackOverflowFromCode;
buzbee5ade1d22011-09-09 14:44:52 -0700304 pThrowNullPointerFromCode = ThrowNullPointerFromCode;
305 pThrowArrayBoundsFromCode = ThrowArrayBoundsFromCode;
306 pThrowDivZeroFromCode = ThrowDivZeroFromCode;
307 pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode;
308 pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode;
309 pThrowRuntimeExceptionFromCode = ThrowRuntimeExceptionFromCode;
310 pThrowInternalErrorFromCode = ThrowInternalErrorFromCode;
311 pThrowNoSuchMethodFromCode = ThrowNoSuchMethodFromCode;
buzbee4a3164f2011-09-03 11:25:10 -0700312 pDebugMe = DebugMe;
buzbee3ea4ec52011-08-22 17:37:19 -0700313}
314
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700315void Frame::Next() {
316 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700317 GetMethod()->GetFrameSizeInBytes();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700318 sp_ = reinterpret_cast<Method**>(next_sp);
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700319}
320
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700321uintptr_t Frame::GetPC() const {
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700322 byte* pc_addr = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700323 GetMethod()->GetReturnPcOffsetInBytes();
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700324 return *reinterpret_cast<uintptr_t*>(pc_addr);
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700325}
326
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700327Method* Frame::NextMethod() const {
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700328 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700329 GetMethod()->GetFrameSizeInBytes();
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700330 return *reinterpret_cast<Method**>(next_sp);
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700331}
332
Carl Shapiro61e019d2011-07-14 16:53:09 -0700333void* ThreadStart(void *arg) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700334 UNIMPLEMENTED(FATAL);
Carl Shapirob5573532011-07-12 18:22:59 -0700335 return NULL;
336}
337
Brian Carlstromb765be02011-08-17 23:54:10 -0700338Thread* Thread::Create(const Runtime* runtime) {
Elliott Hughesdcc24742011-09-07 14:02:44 -0700339 UNIMPLEMENTED(FATAL) << "need to pass in a java.lang.Thread";
340
Elliott Hughesbe759c62011-09-08 19:38:21 -0700341 size_t stack_size = runtime->GetDefaultStackSize();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700342
343 Thread* new_thread = new Thread;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700344
345 pthread_attr_t attr;
Elliott Hughese27955c2011-08-26 15:21:24 -0700346 errno = pthread_attr_init(&attr);
347 if (errno != 0) {
348 PLOG(FATAL) << "pthread_attr_init failed";
349 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700350
Elliott Hughese27955c2011-08-26 15:21:24 -0700351 errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
352 if (errno != 0) {
353 PLOG(FATAL) << "pthread_attr_setdetachstate(PTHREAD_CREATE_DETACHED) failed";
354 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700355
Elliott Hughese27955c2011-08-26 15:21:24 -0700356 errno = pthread_attr_setstacksize(&attr, stack_size);
357 if (errno != 0) {
358 PLOG(FATAL) << "pthread_attr_setstacksize(" << stack_size << ") failed";
359 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700360
Elliott Hughesbe759c62011-09-08 19:38:21 -0700361 errno = pthread_create(&new_thread->pthread_, &attr, ThreadStart, new_thread);
Elliott Hughese27955c2011-08-26 15:21:24 -0700362 if (errno != 0) {
363 PLOG(FATAL) << "pthread_create failed";
364 }
365
366 errno = pthread_attr_destroy(&attr);
367 if (errno != 0) {
368 PLOG(FATAL) << "pthread_attr_destroy failed";
369 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700370
Elliott Hughesdcc24742011-09-07 14:02:44 -0700371 // TODO: get the "daemon" field from the java.lang.Thread.
372 // new_thread->is_daemon_ = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
373
Carl Shapiro61e019d2011-07-14 16:53:09 -0700374 return new_thread;
375}
376
Elliott Hughesdcc24742011-09-07 14:02:44 -0700377Thread* Thread::Attach(const Runtime* runtime, const char* name, bool as_daemon) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700378 Thread* self = new Thread;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700379
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700380 self->tid_ = ::art::GetTid();
Elliott Hughesbe759c62011-09-08 19:38:21 -0700381 self->pthread_ = pthread_self();
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700382 self->is_daemon_ = as_daemon;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700383
Elliott Hughesbe759c62011-09-08 19:38:21 -0700384 self->InitStackHwm();
385
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700386 self->state_ = kRunnable;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700387
Elliott Hughesdcc24742011-09-07 14:02:44 -0700388 SetThreadName(name);
389
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700390 errno = pthread_setspecific(Thread::pthread_key_self_, self);
Elliott Hughesa5780da2011-07-17 11:39:39 -0700391 if (errno != 0) {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700392 PLOG(FATAL) << "pthread_setspecific failed";
Elliott Hughesa5780da2011-07-17 11:39:39 -0700393 }
394
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700395 self->jni_env_ = new JNIEnvExt(self, runtime->GetJavaVM());
Elliott Hughes330304d2011-08-12 14:28:05 -0700396
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700397 runtime->GetThreadList()->Register(self);
398
399 // If we're the main thread, ClassLinker won't be created until after we're attached,
400 // so that thread needs a two-stage attach. Regular threads don't need this hack.
401 if (self->thin_lock_id_ != ThreadList::kMainId) {
402 self->CreatePeer(name, as_daemon);
403 }
404
405 return self;
406}
407
408void Thread::CreatePeer(const char* name, bool as_daemon) {
409 ScopedThreadStateChange tsc(Thread::Current(), Thread::kNative);
410
411 JNIEnv* env = jni_env_;
412
413 jobject thread_group = NULL;
414 jobject thread_name = env->NewStringUTF(name);
Elliott Hughes8daa0922011-09-11 13:46:25 -0700415 jint thread_priority = GetNativePriority();
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700416 jboolean thread_is_daemon = as_daemon;
417
418 jclass c = env->FindClass("java/lang/Thread");
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700419 jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700420
Elliott Hughes8daa0922011-09-11 13:46:25 -0700421 jobject peer = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
422 peer_ = env->NewGlobalRef(peer);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700423}
424
Elliott Hughesbe759c62011-09-08 19:38:21 -0700425void Thread::InitStackHwm() {
426 pthread_attr_t attributes;
427 errno = pthread_getattr_np(pthread_, &attributes);
428 if (errno != 0) {
429 PLOG(FATAL) << "pthread_getattr_np failed";
430 }
431
Elliott Hughesbe759c62011-09-08 19:38:21 -0700432 void* stack_base;
433 size_t stack_size;
434 errno = pthread_attr_getstack(&attributes, &stack_base, &stack_size);
435 if (errno != 0) {
436 PLOG(FATAL) << "pthread_attr_getstack failed";
437 }
438
Elliott Hughesbe759c62011-09-08 19:38:21 -0700439 if (stack_size <= kStackOverflowReservedBytes) {
440 LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size << " bytes)";
441 }
Elliott Hughes449b4bd2011-09-09 12:01:38 -0700442
443 // stack_base is the "lowest addressable byte" of the stack.
444 // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room
445 // to throw a StackOverflowError.
buzbeecefd1872011-09-09 09:59:52 -0700446 stack_end_ = reinterpret_cast<byte*>(stack_base) + kStackOverflowReservedBytes;
Elliott Hughes449b4bd2011-09-09 12:01:38 -0700447
448 // Sanity check.
449 int stack_variable;
450 CHECK_GT(&stack_variable, (void*) stack_end_);
Elliott Hughesbe759c62011-09-08 19:38:21 -0700451
452 errno = pthread_attr_destroy(&attributes);
453 if (errno != 0) {
454 PLOG(FATAL) << "pthread_attr_destroy failed";
455 }
456}
457
Elliott Hughesa0957642011-09-02 14:27:33 -0700458void Thread::Dump(std::ostream& os) const {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700459 /*
460 * Get the java.lang.Thread object. This function gets called from
461 * some weird debug contexts, so it's possible that there's a GC in
462 * progress on some other thread. To decrease the chances of the
463 * thread object being moved out from under us, we add the reference
464 * to the tracked allocation list, which pins it in place.
465 *
466 * If threadObj is NULL, the thread is still in the process of being
467 * attached to the VM, and there's really nothing interesting to
468 * say about it yet.
469 */
470 os << "TODO: pin Thread before dumping\n";
471#if 0
Elliott Hughesdcc24742011-09-07 14:02:44 -0700472 // TODO: dalvikvm had this limitation, but we probably still want to do our best.
473 if (peer_ == NULL) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700474 LOGI("Can't dump thread %d: threadObj not set", threadId);
475 return;
476 }
Elliott Hughesdcc24742011-09-07 14:02:44 -0700477 dvmAddTrackedAlloc(peer_, NULL);
Elliott Hughesd92bec42011-09-02 17:04:36 -0700478#endif
479
480 DumpState(os);
481 DumpStack(os);
482
483#if 0
Elliott Hughesdcc24742011-09-07 14:02:44 -0700484 dvmReleaseTrackedAlloc(peer_, NULL);
Elliott Hughesd92bec42011-09-02 17:04:36 -0700485#endif
Elliott Hughesa0957642011-09-02 14:27:33 -0700486}
487
Elliott Hughesd92bec42011-09-02 17:04:36 -0700488std::string GetSchedulerGroup(pid_t tid) {
489 // /proc/<pid>/group looks like this:
490 // 2:devices:/
491 // 1:cpuacct,cpu:/
492 // We want the third field from the line whose second field contains the "cpu" token.
493 std::string cgroup_file;
494 if (!ReadFileToString("/proc/self/cgroup", &cgroup_file)) {
495 return "";
496 }
497 std::vector<std::string> cgroup_lines;
498 Split(cgroup_file, '\n', cgroup_lines);
499 for (size_t i = 0; i < cgroup_lines.size(); ++i) {
500 std::vector<std::string> cgroup_fields;
501 Split(cgroup_lines[i], ':', cgroup_fields);
502 std::vector<std::string> cgroups;
503 Split(cgroup_fields[1], ',', cgroups);
504 for (size_t i = 0; i < cgroups.size(); ++i) {
505 if (cgroups[i] == "cpu") {
506 return cgroup_fields[2].substr(1); // Skip the leading slash.
507 }
508 }
509 }
510 return "";
511}
512
513void Thread::DumpState(std::ostream& os) const {
514 std::string thread_name("unknown");
515 int priority = -1;
Elliott Hughesdcc24742011-09-07 14:02:44 -0700516
Elliott Hughesd92bec42011-09-02 17:04:36 -0700517#if 0 // TODO
518 nameStr = (StringObject*) dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_name);
519 threadName = dvmCreateCstrFromString(nameStr);
520 priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority);
Elliott Hughesd92bec42011-09-02 17:04:36 -0700521#else
Elliott Hughesdcc24742011-09-07 14:02:44 -0700522 {
523 // TODO: this may be truncated; we should use the java.lang.Thread 'name' field instead.
524 std::string stats;
525 if (ReadFileToString(StringPrintf("/proc/self/task/%d/stat", GetTid()).c_str(), &stats)) {
526 size_t start = stats.find('(') + 1;
527 size_t end = stats.find(')') - start;
528 thread_name = stats.substr(start, end);
529 }
530 }
Elliott Hughesd92bec42011-09-02 17:04:36 -0700531 priority = -1;
Elliott Hughesd92bec42011-09-02 17:04:36 -0700532#endif
533
534 int policy;
535 sched_param sp;
Elliott Hughesbe759c62011-09-08 19:38:21 -0700536 errno = pthread_getschedparam(pthread_, &policy, &sp);
Elliott Hughesd92bec42011-09-02 17:04:36 -0700537 if (errno != 0) {
538 PLOG(FATAL) << "pthread_getschedparam failed";
539 }
540
541 std::string scheduler_group(GetSchedulerGroup(GetTid()));
542 if (scheduler_group.empty()) {
543 scheduler_group = "default";
544 }
545
546 std::string group_name("(null; initializing?)");
547#if 0
548 groupObj = (Object*) dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_group);
549 if (groupObj != NULL) {
550 nameStr = (StringObject*) dvmGetFieldObject(groupObj, gDvm.offJavaLangThreadGroup_name);
551 groupName = dvmCreateCstrFromString(nameStr);
552 }
553#else
554 group_name = "TODO";
555#endif
556
557 os << '"' << thread_name << '"';
Elliott Hughesdcc24742011-09-07 14:02:44 -0700558 if (is_daemon_) {
Elliott Hughesd92bec42011-09-02 17:04:36 -0700559 os << " daemon";
560 }
561 os << " prio=" << priority
Elliott Hughesdcc24742011-09-07 14:02:44 -0700562 << " tid=" << GetThinLockId()
Elliott Hughesd92bec42011-09-02 17:04:36 -0700563 << " " << state_ << "\n";
564
565 int suspend_count = 0; // TODO
566 int debug_suspend_count = 0; // TODO
Elliott Hughesd92bec42011-09-02 17:04:36 -0700567 os << " | group=\"" << group_name << "\""
568 << " sCount=" << suspend_count
569 << " dsCount=" << debug_suspend_count
Elliott Hughesdcc24742011-09-07 14:02:44 -0700570 << " obj=" << reinterpret_cast<void*>(peer_)
Elliott Hughesd92bec42011-09-02 17:04:36 -0700571 << " self=" << reinterpret_cast<const void*>(this) << "\n";
572 os << " | sysTid=" << GetTid()
573 << " nice=" << getpriority(PRIO_PROCESS, GetTid())
574 << " sched=" << policy << "/" << sp.sched_priority
575 << " cgrp=" << scheduler_group
576 << " handle=" << GetImpl() << "\n";
577
578 // Grab the scheduler stats for this thread.
579 std::string scheduler_stats;
580 if (ReadFileToString(StringPrintf("/proc/self/task/%d/schedstat", GetTid()).c_str(), &scheduler_stats)) {
581 scheduler_stats.resize(scheduler_stats.size() - 1); // Lose the trailing '\n'.
582 } else {
583 scheduler_stats = "0 0 0";
584 }
585
586 int utime = 0;
587 int stime = 0;
588 int task_cpu = 0;
589 std::string stats;
590 if (ReadFileToString(StringPrintf("/proc/self/task/%d/stat", GetTid()).c_str(), &stats)) {
591 // Skip the command, which may contain spaces.
592 stats = stats.substr(stats.find(')') + 2);
593 // Extract the three fields we care about.
594 std::vector<std::string> fields;
595 Split(stats, ' ', fields);
596 utime = strtoull(fields[11].c_str(), NULL, 10);
597 stime = strtoull(fields[12].c_str(), NULL, 10);
598 task_cpu = strtoull(fields[36].c_str(), NULL, 10);
599 }
600
601 os << " | schedstat=( " << scheduler_stats << " )"
602 << " utm=" << utime
603 << " stm=" << stime
604 << " core=" << task_cpu
605 << " HZ=" << sysconf(_SC_CLK_TCK) << "\n";
606}
607
608void Thread::DumpStack(std::ostream& os) const {
609 os << "UNIMPLEMENTED: Thread::DumpStack\n";
Elliott Hughese27955c2011-08-26 15:21:24 -0700610}
611
Elliott Hughesbe759c62011-09-08 19:38:21 -0700612void Thread::ThreadExitCallback(void* arg) {
613 Thread* self = reinterpret_cast<Thread*>(arg);
614 LOG(FATAL) << "Native thread exited without calling DetachCurrentThread: " << *self;
Carl Shapirob5573532011-07-12 18:22:59 -0700615}
616
Elliott Hughesbe759c62011-09-08 19:38:21 -0700617void Thread::Startup() {
Carl Shapirob5573532011-07-12 18:22:59 -0700618 // Allocate a TLS slot.
Elliott Hughesbe759c62011-09-08 19:38:21 -0700619 errno = pthread_key_create(&Thread::pthread_key_self_, Thread::ThreadExitCallback);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700620 if (errno != 0) {
Elliott Hughesbe759c62011-09-08 19:38:21 -0700621 PLOG(FATAL) << "pthread_key_create failed";
Carl Shapirob5573532011-07-12 18:22:59 -0700622 }
623
624 // Double-check the TLS slot allocation.
625 if (pthread_getspecific(pthread_key_self_) != NULL) {
Elliott Hughesbe759c62011-09-08 19:38:21 -0700626 LOG(FATAL) << "newly-created pthread TLS slot is not NULL";
Carl Shapirob5573532011-07-12 18:22:59 -0700627 }
628
629 // TODO: initialize other locks and condition variables
Carl Shapirob5573532011-07-12 18:22:59 -0700630}
631
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700632void Thread::Shutdown() {
633 errno = pthread_key_delete(Thread::pthread_key_self_);
634 if (errno != 0) {
635 PLOG(WARNING) << "pthread_key_delete failed";
636 }
637}
638
Elliott Hughesdcc24742011-09-07 14:02:44 -0700639Thread::Thread()
Elliott Hughes02b48d12011-09-07 17:15:51 -0700640 : peer_(NULL),
Elliott Hughes8daa0922011-09-11 13:46:25 -0700641 wait_mutex_("Thread wait mutex"),
642 wait_monitor_(NULL),
643 interrupted_(false),
644 stack_end_(NULL),
Elliott Hughesdcc24742011-09-07 14:02:44 -0700645 top_of_managed_stack_(),
646 native_to_managed_record_(NULL),
647 top_sirt_(NULL),
648 jni_env_(NULL),
649 exception_(NULL),
650 suspend_count_(0),
651 class_loader_override_(NULL) {
Elliott Hughes5fe594f2011-09-08 12:33:17 -0700652 InitCpu();
Elliott Hughesdcc24742011-09-07 14:02:44 -0700653 InitFunctionPointers();
Elliott Hughes8daa0922011-09-11 13:46:25 -0700654 thin_lock_id_ = Runtime::Current()->GetThreadList()->AllocThreadId();
Elliott Hughesdcc24742011-09-07 14:02:44 -0700655}
656
Elliott Hughes02b48d12011-09-07 17:15:51 -0700657void MonitorExitVisitor(const Object* object, void*) {
658 Object* entered_monitor = const_cast<Object*>(object);
659 entered_monitor->MonitorExit();;
660}
661
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700662Thread::~Thread() {
Elliott Hughes02b48d12011-09-07 17:15:51 -0700663 // TODO: check we're not calling the JNI DetachCurrentThread function from
664 // a call stack that includes managed frames. (It's only valid if the stack is all-native.)
665
666 // On thread detach, all monitors entered with JNI MonitorEnter are automatically exited.
667 jni_env_->monitors.VisitRoots(MonitorExitVisitor, NULL);
668
669 if (IsExceptionPending()) {
670 UNIMPLEMENTED(FATAL) << "threadExitUncaughtException()";
671 }
672
673 // TODO: ThreadGroup.removeThread(this);
674
675 // TODO: this.vmData = 0;
676
677 // TODO: say "bye" to the debugger.
678 //if (gDvm.debuggerConnected) {
679 // dvmDbgPostThreadDeath(self);
680 //}
681
682 // Thread.join() is implemented as an Object.wait() on the Thread.lock
683 // object. Signal anyone who is waiting.
684 //Object* lock = dvmGetFieldObject(self->threadObj, gDvm.offJavaLangThread_lock);
685 //dvmLockObject(self, lock);
686 //dvmObjectNotifyAll(self, lock);
687 //dvmUnlockObject(self, lock);
688 //lock = NULL;
689
Elliott Hughes8daa0922011-09-11 13:46:25 -0700690 // Delete our global reference to the java.lang.Thread.
691 jni_env_->DeleteGlobalRef(peer_);
692 peer_ = NULL;
693
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700694 delete jni_env_;
Elliott Hughes02b48d12011-09-07 17:15:51 -0700695 jni_env_ = NULL;
696
697 SetState(Thread::kTerminated);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700698}
699
Ian Rogers408f79a2011-08-23 18:22:33 -0700700size_t Thread::NumSirtReferences() {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700701 size_t count = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700702 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700703 count += cur->NumberOfReferences();
704 }
705 return count;
706}
707
Ian Rogers408f79a2011-08-23 18:22:33 -0700708bool Thread::SirtContains(jobject obj) {
709 Object** sirt_entry = reinterpret_cast<Object**>(obj);
710 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700711 size_t num_refs = cur->NumberOfReferences();
Ian Rogers408f79a2011-08-23 18:22:33 -0700712 // A SIRT should always have a jobject/jclass as a native method is passed
713 // in a this pointer or a class
714 DCHECK_GT(num_refs, 0u);
Shih-wei Liao2f0ce9d2011-09-01 02:07:58 -0700715 if ((&cur->References()[0] <= sirt_entry) &&
716 (sirt_entry <= (&cur->References()[num_refs - 1]))) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700717 return true;
718 }
719 }
720 return false;
721}
722
Ian Rogers408f79a2011-08-23 18:22:33 -0700723Object* Thread::DecodeJObject(jobject obj) {
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700724 DCHECK(CanAccessDirectReferences());
Ian Rogers408f79a2011-08-23 18:22:33 -0700725 if (obj == NULL) {
726 return NULL;
727 }
728 IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
729 IndirectRefKind kind = GetIndirectRefKind(ref);
730 Object* result;
731 switch (kind) {
732 case kLocal:
733 {
Elliott Hughes69f5bc62011-08-24 09:26:14 -0700734 IndirectReferenceTable& locals = jni_env_->locals;
Elliott Hughescf4c6c42011-09-01 15:16:42 -0700735 result = const_cast<Object*>(locals.Get(ref));
Ian Rogers408f79a2011-08-23 18:22:33 -0700736 break;
737 }
738 case kGlobal:
739 {
740 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
741 IndirectReferenceTable& globals = vm->globals;
742 MutexLock mu(vm->globals_lock);
Elliott Hughescf4c6c42011-09-01 15:16:42 -0700743 result = const_cast<Object*>(globals.Get(ref));
Ian Rogers408f79a2011-08-23 18:22:33 -0700744 break;
745 }
746 case kWeakGlobal:
747 {
748 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
749 IndirectReferenceTable& weak_globals = vm->weak_globals;
750 MutexLock mu(vm->weak_globals_lock);
Elliott Hughescf4c6c42011-09-01 15:16:42 -0700751 result = const_cast<Object*>(weak_globals.Get(ref));
Ian Rogers408f79a2011-08-23 18:22:33 -0700752 if (result == kClearedJniWeakGlobal) {
753 // This is a special case where it's okay to return NULL.
754 return NULL;
755 }
756 break;
757 }
758 case kSirtOrInvalid:
759 default:
760 // TODO: make stack indirect reference table lookup more efficient
761 // Check if this is a local reference in the SIRT
762 if (SirtContains(obj)) {
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700763 result = *reinterpret_cast<Object**>(obj); // Read from SIRT
Elliott Hughesc5bfa8f2011-08-30 14:32:49 -0700764 } else if (jni_env_->work_around_app_jni_bugs) {
Ian Rogers408f79a2011-08-23 18:22:33 -0700765 // Assume an invalid local reference is actually a direct pointer.
766 result = reinterpret_cast<Object*>(obj);
767 } else {
Elliott Hughesa2501992011-08-26 19:39:54 -0700768 result = kInvalidIndirectRefObject;
Ian Rogers408f79a2011-08-23 18:22:33 -0700769 }
770 }
771
772 if (result == NULL) {
Elliott Hughesa2501992011-08-26 19:39:54 -0700773 LOG(ERROR) << "JNI ERROR (app bug): use of deleted " << kind << ": " << obj;
774 JniAbort(NULL);
775 } else {
776 if (result != kInvalidIndirectRefObject) {
777 Heap::VerifyObject(result);
778 }
Ian Rogers408f79a2011-08-23 18:22:33 -0700779 }
Ian Rogers408f79a2011-08-23 18:22:33 -0700780 return result;
781}
782
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700783class CountStackDepthVisitor : public Thread::StackVisitor {
784 public:
Ian Rogersaaa20802011-09-11 21:47:37 -0700785 CountStackDepthVisitor() : depth_(0) {}
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700786 virtual bool VisitFrame(const Frame&) {
Ian Rogersaaa20802011-09-11 21:47:37 -0700787 ++depth_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700788 return true;
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700789 }
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700790
791 int GetDepth() const {
Ian Rogersaaa20802011-09-11 21:47:37 -0700792 return depth_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700793 }
794
795 private:
Ian Rogersaaa20802011-09-11 21:47:37 -0700796 uint32_t depth_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700797};
798
Ian Rogersaaa20802011-09-11 21:47:37 -0700799//
800class BuildInternalStackTraceVisitor : public Thread::StackVisitor {
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700801 public:
Ian Rogersaaa20802011-09-11 21:47:37 -0700802 explicit BuildInternalStackTraceVisitor(int depth, ScopedJniThreadState& ts) : count_(0) {
803 // Allocate method trace with an extra slot that will hold the PC trace
804 method_trace_ = Runtime::Current()->GetClassLinker()->
805 AllocObjectArray<Object>(depth + 1);
806 // Register a local reference as IntArray::Alloc may trigger GC
807 local_ref_ = AddLocalReference<jobject>(ts.Env(), method_trace_);
808 pc_trace_ = IntArray::Alloc(depth);
809#ifdef MOVING_GARBAGE_COLLECTOR
810 // Re-read after potential GC
811 method_trace = Decode<ObjectArray<Object>*>(ts.Env(), local_ref_);
812#endif
813 // Save PC trace in last element of method trace, also places it into the
814 // object graph.
815 method_trace_->Set(depth, pc_trace_);
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700816 }
817
Ian Rogersaaa20802011-09-11 21:47:37 -0700818 virtual ~BuildInternalStackTraceVisitor() {}
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700819
820 virtual bool VisitFrame(const Frame& frame) {
Ian Rogersaaa20802011-09-11 21:47:37 -0700821 method_trace_->Set(count_, frame.GetMethod());
822 pc_trace_->Set(count_, frame.GetPC());
823 ++count_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700824 return true;
825 }
826
Ian Rogersaaa20802011-09-11 21:47:37 -0700827 jobject GetInternalStackTrace() const {
828 return local_ref_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700829 }
830
831 private:
Ian Rogersaaa20802011-09-11 21:47:37 -0700832 // Current position down stack trace
833 uint32_t count_;
834 // Array of return PC values
835 IntArray* pc_trace_;
836 // An array of the methods on the stack, the last entry is a reference to the
837 // PC trace
838 ObjectArray<Object>* method_trace_;
839 // Local indirect reference table entry for method trace
840 jobject local_ref_;
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700841};
842
Ian Rogersaaa20802011-09-11 21:47:37 -0700843void Thread::WalkStack(StackVisitor* visitor) const {
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700844 Frame frame = Thread::Current()->GetTopOfStack();
845 // TODO: enable this CHECK after native_to_managed_record_ is initialized during startup.
846 // CHECK(native_to_managed_record_ != NULL);
847 NativeToManagedRecord* record = native_to_managed_record_;
848
849 while (frame.GetSP()) {
850 for ( ; frame.GetMethod() != 0; frame.Next()) {
851 visitor->VisitFrame(frame);
852 }
853 if (record == NULL) {
854 break;
855 }
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700856 frame.SetSP(reinterpret_cast<art::Method**>(record->last_top_of_managed_stack)); // last_tos should return Frame instead of sp?
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700857 record = record->link;
858 }
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700859}
860
Ian Rogersaaa20802011-09-11 21:47:37 -0700861jobject Thread::CreateInternalStackTrace() const {
862 // Compute depth of stack
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700863 CountStackDepthVisitor count_visitor;
864 WalkStack(&count_visitor);
865 int32_t depth = count_visitor.GetDepth();
Shih-wei Liao44175362011-08-28 16:59:17 -0700866
Ian Rogersaaa20802011-09-11 21:47:37 -0700867 // Transition into runnable state to work on Object*/Array*
868 ScopedJniThreadState ts(jni_env_);
869
870 // Build internal stack trace
871 BuildInternalStackTraceVisitor build_trace_visitor(depth, ts);
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700872 WalkStack(&build_trace_visitor);
Shih-wei Liao44175362011-08-28 16:59:17 -0700873
Ian Rogersaaa20802011-09-11 21:47:37 -0700874 return build_trace_visitor.GetInternalStackTrace();
875}
876
877jobjectArray Thread::InternalStackTraceToStackTraceElementArray(jobject internal,
878 JNIEnv* env) {
879 // Transition into runnable state to work on Object*/Array*
880 ScopedJniThreadState ts(env);
881
882 // Decode the internal stack trace into the depth, method trace and PC trace
883 ObjectArray<Object>* method_trace =
884 down_cast<ObjectArray<Object>*>(Decode<Object*>(ts.Env(), internal));
885 int32_t depth = method_trace->GetLength()-1;
886 IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
887
888 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
889
890 // Create java_trace array and place in local reference table
891 ObjectArray<StackTraceElement>* java_traces =
892 class_linker->AllocStackTraceElementArray(depth);
893 jobjectArray result = AddLocalReference<jobjectArray>(ts.Env(), java_traces);
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700894
Shih-wei Liao9b576b42011-08-29 01:45:07 -0700895 for (int32_t i = 0; i < depth; ++i) {
Ian Rogersaaa20802011-09-11 21:47:37 -0700896 // Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
897 Method* method = down_cast<Method*>(method_trace->Get(i));
898 uint32_t native_pc = pc_trace->Get(i);
899 Class* klass = method->GetDeclaringClass();
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700900 const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
Shih-wei Liao44175362011-08-28 16:59:17 -0700901 String* readable_descriptor = String::AllocFromModifiedUtf8(
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700902 PrettyDescriptor(klass->GetDescriptor()).c_str());
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700903
Ian Rogersaaa20802011-09-11 21:47:37 -0700904 // Allocate element, potentially triggering GC
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700905 StackTraceElement* obj =
906 StackTraceElement::Alloc(readable_descriptor,
Shih-wei Liao44175362011-08-28 16:59:17 -0700907 method->GetName(),
Brian Carlstrom4b620ff2011-09-11 01:11:01 -0700908 klass->GetSourceFile(),
Shih-wei Liao44175362011-08-28 16:59:17 -0700909 dex_file.GetLineNumFromPC(method,
Ian Rogersaaa20802011-09-11 21:47:37 -0700910 method->ToDexPC(native_pc)));
911#ifdef MOVING_GARBAGE_COLLECTOR
912 // Re-read after potential GC
913 java_traces = Decode<ObjectArray<Object>*>(ts.Env(), result);
914 method_trace = down_cast<ObjectArray<Object>*>(Decode<Object*>(ts.Env(), internal));
915 pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
916#endif
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700917 java_traces->Set(i, obj);
918 }
Ian Rogersaaa20802011-09-11 21:47:37 -0700919 return result;
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700920}
921
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700922void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
Elliott Hughes37f7a402011-08-22 18:56:01 -0700923 std::string msg;
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700924 va_list args;
925 va_start(args, fmt);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700926 StringAppendV(&msg, fmt, args);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700927 va_end(args);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700928
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700929 // Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700930 CHECK_EQ('L', exception_class_descriptor[0]);
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700931 std::string descriptor(exception_class_descriptor + 1);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700932 CHECK_EQ(';', descriptor[descriptor.length() - 1]);
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700933 descriptor.erase(descriptor.length() - 1);
934
935 JNIEnv* env = GetJniEnv();
936 jclass exception_class = env->FindClass(descriptor.c_str());
937 CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
938 int rc = env->ThrowNew(exception_class, msg.c_str());
939 CHECK_EQ(rc, JNI_OK);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700940}
941
Elliott Hughes79082e32011-08-25 12:07:32 -0700942void Thread::ThrowOutOfMemoryError() {
943 UNIMPLEMENTED(FATAL);
944}
945
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700946Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
947 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
948 DCHECK(class_linker != NULL);
949
950 Frame cur_frame = GetTopOfStack();
951 for (int unwind_depth = 0; ; unwind_depth++) {
952 const Method* cur_method = cur_frame.GetMethod();
953 DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
954 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
955
956 void* handler_addr = FindExceptionHandlerInMethod(cur_method,
957 throw_pc,
958 dex_file,
959 class_linker);
960 if (handler_addr) {
961 *handler_pc = handler_addr;
962 return cur_frame;
963 } else {
964 // Check if we are at the last frame
965 if (cur_frame.HasNext()) {
966 cur_frame.Next();
967 } else {
968 // Either at the top of stack or next frame is native.
969 break;
970 }
971 }
972 }
973 *handler_pc = NULL;
974 return Frame();
975}
976
977void* Thread::FindExceptionHandlerInMethod(const Method* method,
978 void* throw_pc,
979 const DexFile& dex_file,
980 ClassLinker* class_linker) {
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700981 Throwable* exception_obj = exception_;
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700982 exception_ = NULL;
983
984 intptr_t dex_pc = -1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700985 const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700986 DexFile::CatchHandlerIterator iter;
987 for (iter = dex_file.dexFindCatchHandler(*code_item,
988 method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
989 !iter.HasNext();
990 iter.Next()) {
991 Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
992 DCHECK(klass != NULL);
993 if (exception_obj->InstanceOf(klass)) {
994 dex_pc = iter.Get().address_;
995 break;
996 }
997 }
998
999 exception_ = exception_obj;
1000 if (iter.HasNext()) {
1001 return NULL;
1002 } else {
1003 return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
1004 }
1005}
1006
Elliott Hughes410c0c82011-09-01 17:58:25 -07001007void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
1008 //(*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg);
1009 //(*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg);
1010 jni_env_->locals.VisitRoots(visitor, arg);
1011 jni_env_->monitors.VisitRoots(visitor, arg);
1012 // visitThreadStack(visitor, thread, arg);
1013 UNIMPLEMENTED(WARNING) << "some per-Thread roots not visited";
1014}
1015
Ian Rogersb033c752011-07-20 12:22:35 -07001016static const char* kStateNames[] = {
1017 "New",
1018 "Runnable",
1019 "Blocked",
1020 "Waiting",
1021 "TimedWaiting",
1022 "Native",
1023 "Terminated",
1024};
1025std::ostream& operator<<(std::ostream& os, const Thread::State& state) {
1026 if (state >= Thread::kNew && state <= Thread::kTerminated) {
1027 os << kStateNames[state-Thread::kNew];
1028 } else {
1029 os << "State[" << static_cast<int>(state) << "]";
1030 }
1031 return os;
1032}
1033
Elliott Hughes330304d2011-08-12 14:28:05 -07001034std::ostream& operator<<(std::ostream& os, const Thread& thread) {
1035 os << "Thread[" << &thread
Elliott Hughese27955c2011-08-26 15:21:24 -07001036 << ",pthread_t=" << thread.GetImpl()
1037 << ",tid=" << thread.GetTid()
Elliott Hughesdcc24742011-09-07 14:02:44 -07001038 << ",id=" << thread.GetThinLockId()
Elliott Hughes8daa0922011-09-11 13:46:25 -07001039 << ",state=" << thread.GetState()
1040 << ",peer=" << thread.GetPeer()
1041 << "]";
Elliott Hughes330304d2011-08-12 14:28:05 -07001042 return os;
1043}
1044
Elliott Hughes8daa0922011-09-11 13:46:25 -07001045} // namespace art