runtime.cc revision 2692b573a56cd63a3c8c8aa1636e3766b6d8c9c4
1// Copyright 2011 Google Inc. All Rights Reserved. 2 3#include "runtime.h" 4 5#include <signal.h> 6 7#include <cstdio> 8#include <cstdlib> 9#include <limits> 10#include <vector> 11 12#include "class_linker.h" 13#include "class_loader.h" 14#include "debugger.h" 15#include "heap.h" 16#include "image.h" 17#include "intern_table.h" 18#include "jni_internal.h" 19#include "monitor.h" 20#include "oat_file.h" 21#include "ScopedLocalRef.h" 22#include "signal_catcher.h" 23#include "space.h" 24#include "thread.h" 25#include "thread_list.h" 26#include "UniquePtr.h" 27 28// TODO: this drags in cutil/log.h, which conflicts with our logging.h. 29#include "JniConstants.h" 30 31namespace art { 32 33Runtime* Runtime::instance_ = NULL; 34 35Runtime::Runtime() 36 : is_zygote_(false), 37 default_stack_size_(Thread::kDefaultStackSize), 38 monitor_list_(NULL), 39 thread_list_(NULL), 40 intern_table_(NULL), 41 class_linker_(NULL), 42 signal_catcher_(NULL), 43 java_vm_(NULL), 44 jni_stub_array_(NULL), 45 abstract_method_error_stub_array_(NULL), 46 started_(false), 47 vfprintf_(NULL), 48 exit_(NULL), 49 abort_(NULL), 50 stats_enabled_(false), 51 tracer_(NULL) { 52 for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) { 53 resolution_stub_array_[i] = NULL; 54 } 55 for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { 56 callee_save_method_[i] = NULL; 57 } 58} 59 60Runtime::~Runtime() { 61 Dbg::StopJdwp(); 62 63 // Make sure our internal threads are dead before we start tearing down things they're using. 64 delete signal_catcher_; 65 // TODO: GC thread. 66 67 // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended. 68 delete thread_list_; 69 delete monitor_list_; 70 71 delete class_linker_; 72 Heap::Destroy(); 73 delete intern_table_; 74 delete java_vm_; 75 Thread::Shutdown(); 76 // TODO: acquire a static mutex on Runtime to avoid racing. 77 CHECK(instance_ == NULL || instance_ == this); 78 instance_ = NULL; 79} 80 81static bool gAborting = false; 82 83struct AbortState { 84 void Dump(std::ostream& os) { 85 if (gAborting) { 86 os << "Runtime aborting --- recursively, so no thread-specific detail!\n"; 87 return; 88 } 89 gAborting = true; 90 os << "Runtime aborting...\n"; 91 Thread* self = Thread::Current(); 92 if (self == NULL) { 93 os << "(Aborting thread was not attached to runtime!)\n"; 94 } else { 95 self->Dump(os, true); 96 } 97 } 98}; 99 100void Runtime::Abort(const char* file, int line) { 101 // Get any pending output out of the way. 102 fflush(NULL); 103 104 // Many people have difficulty distinguish aborts from crashes, 105 // so be explicit. 106 AbortState state; 107 LOG(ERROR) << Dumpable<AbortState>(state); 108 109 // Perform any platform-specific pre-abort actions. 110 PlatformAbort(file, line); 111 112 // use abort hook if we have one 113 if (Runtime::Current() != NULL && Runtime::Current()->abort_ != NULL) { 114 Runtime::Current()->abort_(); 115 // notreached 116 } 117 118 // If we call abort(3) on a device, all threads in the process 119 // receive SIGABRT. debuggerd dumps the stack trace of the main 120 // thread, whether or not that was the thread that failed. By 121 // stuffing a value into a bogus address, we cause a segmentation 122 // fault in the current thread, and get a useful log from debuggerd. 123 // We can also trivially tell the difference between a VM crash and 124 // a deliberate abort by looking at the fault address. 125 *reinterpret_cast<char*>(0xdeadd00d) = 38; 126 abort(); 127 // notreached 128} 129 130void Runtime::CallExitHook(jint status) { 131 if (exit_ != NULL) { 132 ScopedThreadStateChange tsc(Thread::Current(), Thread::kNative); 133 exit_(status); 134 LOG(WARNING) << "Exit hook returned instead of exiting!"; 135 } 136} 137 138// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify 139// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and 140// [gG] gigabytes. 141// 142// "s" should point just past the "-Xm?" part of the string. 143// "div" specifies a divisor, e.g. 1024 if the value must be a multiple 144// of 1024. 145// 146// The spec says the -Xmx and -Xms options must be multiples of 1024. It 147// doesn't say anything about -Xss. 148// 149// Returns 0 (a useless size) if "s" is malformed or specifies a low or 150// non-evenly-divisible value. 151// 152size_t ParseMemoryOption(const char* s, size_t div) { 153 // strtoul accepts a leading [+-], which we don't want, 154 // so make sure our string starts with a decimal digit. 155 if (isdigit(*s)) { 156 const char* s2; 157 size_t val = strtoul(s, (char**)&s2, 10); 158 if (s2 != s) { 159 // s2 should be pointing just after the number. 160 // If this is the end of the string, the user 161 // has specified a number of bytes. Otherwise, 162 // there should be exactly one more character 163 // that specifies a multiplier. 164 if (*s2 != '\0') { 165 // The remainder of the string is either a single multiplier 166 // character, or nothing to indicate that the value is in 167 // bytes. 168 char c = *s2++; 169 if (*s2 == '\0') { 170 size_t mul; 171 if (c == '\0') { 172 mul = 1; 173 } else if (c == 'k' || c == 'K') { 174 mul = KB; 175 } else if (c == 'm' || c == 'M') { 176 mul = MB; 177 } else if (c == 'g' || c == 'G') { 178 mul = GB; 179 } else { 180 // Unknown multiplier character. 181 return 0; 182 } 183 184 if (val <= std::numeric_limits<size_t>::max() / mul) { 185 val *= mul; 186 } else { 187 // Clamp to a multiple of 1024. 188 val = std::numeric_limits<size_t>::max() & ~(1024-1); 189 } 190 } else { 191 // There's more than one character after the numeric part. 192 return 0; 193 } 194 } 195 // The man page says that a -Xm value must be a multiple of 1024. 196 if (val % div == 0) { 197 return val; 198 } 199 } 200 } 201 return 0; 202} 203 204size_t ParseIntegerOrDie(const StringPiece& s) { 205 StringPiece::size_type colon = s.find(':'); 206 if (colon == StringPiece::npos) { 207 LOG(FATAL) << "Missing integer: " << s; 208 } 209 const char* begin = &s.data()[colon + 1]; 210 char* end; 211 size_t result = strtoul(begin, &end, 10); 212 if (begin == end || *end != '\0') { 213 LOG(FATAL) << "Failed to parse integer in: " << s; 214 } 215 return result; 216} 217 218void LoadJniLibrary(JavaVMExt* vm, const char* name) { 219 // TODO: OS_SHARED_LIB_FORMAT_STR 220 std::string mapped_name(StringPrintf("lib%s.so", name)); 221 std::string reason; 222 if (!vm->LoadNativeLibrary(mapped_name, NULL, reason)) { 223 LOG(FATAL) << "LoadNativeLibrary failed for \"" << mapped_name << "\": " 224 << reason; 225 } 226} 227 228Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) { 229 UniquePtr<ParsedOptions> parsed(new ParsedOptions()); 230 bool compiler = false; 231 const char* boot_class_path = getenv("BOOTCLASSPATH"); 232 if (boot_class_path != NULL) { 233 parsed->boot_class_path_ = getenv("BOOTCLASSPATH"); 234 } 235 const char* class_path = getenv("CLASSPATH"); 236 if (class_path != NULL) { 237 parsed->class_path_ = getenv("CLASSPATH"); 238 } 239#ifdef NDEBUG 240 // -Xcheck:jni is off by default for regular builds... 241 parsed->check_jni_ = false; 242#else 243 // ...but on by default in debug builds. 244 parsed->check_jni_ = true; 245#endif 246 247 parsed->heap_initial_size_ = Heap::kInitialSize; 248 parsed->heap_maximum_size_ = Heap::kMaximumSize; 249 parsed->heap_growth_limit_ = 0; // 0 means no growth limit 250 parsed->stack_size_ = Thread::kDefaultStackSize; 251 252 parsed->is_zygote_ = false; 253 254 parsed->jni_globals_max_ = 0; 255 parsed->lock_profiling_threshold_ = 0; 256 parsed->hook_is_sensitive_thread_ = NULL; 257 258 parsed->hook_vfprintf_ = vfprintf; 259 parsed->hook_exit_ = exit; 260 parsed->hook_abort_ = abort; 261 262 for (size_t i = 0; i < options.size(); ++i) { 263 const StringPiece& option = options[i].first; 264 if (true && options[0].first == "-Xzygote") { 265 LOG(INFO) << "option[" << i << "]=" << option; 266 } 267 if (option.starts_with("-Xbootclasspath:")) { 268 parsed->boot_class_path_ = option.substr(strlen("-Xbootclasspath:")).data(); 269 } else if (option == "-classpath" || option == "-cp") { 270 // TODO: support -Djava.class.path 271 i++; 272 if (i == options.size()) { 273 // TODO: usage 274 LOG(FATAL) << "Missing required class path value for " << option; 275 return NULL; 276 } 277 const StringPiece& value = options[i].first; 278 parsed->class_path_ = value.data(); 279 } else if (option.starts_with("-Ximage:")) { 280 parsed->images_.push_back(option.substr(strlen("-Ximage:")).data()); 281 } else if (option.starts_with("-Xcheck:jni")) { 282 parsed->check_jni_ = true; 283 } else if (option.starts_with("-Xrunjdwp:") || option.starts_with("-agentlib:jdwp=")) { 284 std::string tail(option.substr(option[1] == 'X' ? 10 : 15).ToString()); 285 if (tail == "help" || !Dbg::ParseJdwpOptions(tail)) { 286 LOG(FATAL) << "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n" 287 << "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n"; 288 return NULL; 289 } 290 } else if (option.starts_with("-Xms")) { 291 size_t size = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024); 292 if (size == 0) { 293 if (ignore_unrecognized) { 294 continue; 295 } 296 // TODO: usage 297 LOG(FATAL) << "Failed to parse " << option; 298 return NULL; 299 } 300 parsed->heap_initial_size_ = size; 301 } else if (option.starts_with("-Xmx")) { 302 size_t size = ParseMemoryOption(option.substr(strlen("-Xmx")).data(), 1024); 303 if (size == 0) { 304 if (ignore_unrecognized) { 305 continue; 306 } 307 // TODO: usage 308 LOG(FATAL) << "Failed to parse " << option; 309 return NULL; 310 } 311 parsed->heap_maximum_size_ = size; 312 } else if (option.starts_with("-XX:HeapGrowthLimit=")) { 313 size_t size = ParseMemoryOption(option.substr(strlen("-XX:HeapGrowthLimit=")).data(), 1024); 314 if (size == 0) { 315 if (ignore_unrecognized) { 316 continue; 317 } 318 // TODO: usage 319 LOG(FATAL) << "Failed to parse " << option; 320 return NULL; 321 } 322 parsed->heap_growth_limit_ = size; 323 } else if (option.starts_with("-Xss")) { 324 size_t size = ParseMemoryOption(option.substr(strlen("-Xss")).data(), 1); 325 if (size == 0) { 326 if (ignore_unrecognized) { 327 continue; 328 } 329 // TODO: usage 330 LOG(FATAL) << "Failed to parse " << option; 331 return NULL; 332 } 333 parsed->stack_size_ = size; 334 } else if (option.starts_with("-D")) { 335 parsed->properties_.push_back(option.substr(strlen("-D")).data()); 336 } else if (option.starts_with("-Xjnitrace:")) { 337 parsed->jni_trace_ = option.substr(strlen("-Xjnitrace:")).data(); 338 } else if (option == "compiler") { 339 compiler = true; 340 } else if (option == "-Xzygote") { 341 parsed->is_zygote_ = true; 342 } else if (option.starts_with("-verbose:")) { 343 std::vector<std::string> verbose_options; 344 Split(option.substr(strlen("-verbose:")).data(), ',', verbose_options); 345 for (size_t i = 0; i < verbose_options.size(); ++i) { 346 if (verbose_options[i] == "class") { 347 gLogVerbosity.class_linker = true; 348 } else if (verbose_options[i] == "compiler") { 349 gLogVerbosity.compiler = true; 350 } else if (verbose_options[i] == "heap") { 351 gLogVerbosity.heap = true; 352 } else if (verbose_options[i] == "gc") { 353 gLogVerbosity.gc = true; 354 } else if (verbose_options[i] == "jdwp") { 355 gLogVerbosity.jdwp = true; 356 } else if (verbose_options[i] == "jni") { 357 gLogVerbosity.jni = true; 358 } else if (verbose_options[i] == "monitor") { 359 gLogVerbosity.monitor = true; 360 } else if (verbose_options[i] == "startup") { 361 gLogVerbosity.startup = true; 362 } else if (verbose_options[i] == "third-party-jni") { 363 gLogVerbosity.third_party_jni = true; 364 } else if (verbose_options[i] == "threads") { 365 gLogVerbosity.threads = true; 366 } else { 367 LOG(WARNING) << "Ignoring unknown -verbose option: " << verbose_options[i]; 368 } 369 } 370 } else if (option.starts_with("-Xjnigreflimit:")) { 371 parsed->jni_globals_max_ = ParseIntegerOrDie(option); 372 } else if (option.starts_with("-Xlockprofthreshold:")) { 373 parsed->lock_profiling_threshold_ = ParseIntegerOrDie(option); 374 } else if (option.starts_with("-Xstacktracefile:")) { 375// always show stack traces in debug builds 376#ifdef NDEBUG 377 parsed->stack_trace_file_ = option.substr(strlen("-Xstacktracefile:")).data(); 378#endif 379 } else if (option == "sensitiveThread") { 380 parsed->hook_is_sensitive_thread_ = reinterpret_cast<bool (*)()>(options[i].second); 381 } else if (option == "vfprintf") { 382 parsed->hook_vfprintf_ = reinterpret_cast<int (*)(FILE *, const char*, va_list)>(options[i].second); 383 } else if (option == "exit") { 384 parsed->hook_exit_ = reinterpret_cast<void(*)(jint)>(options[i].second); 385 } else if (option == "abort") { 386 parsed->hook_abort_ = reinterpret_cast<void(*)()>(options[i].second); 387 } else if (option == "host-prefix") { 388 parsed->host_prefix_ = reinterpret_cast<const char*>(options[i].second); 389 } else { 390 if (!ignore_unrecognized) { 391 // TODO: print usage via vfprintf 392 LOG(ERROR) << "Unrecognized option " << option; 393 // TODO: this should exit, but for now tolerate unknown options 394 //return NULL; 395 } 396 } 397 } 398 399 if (!compiler && parsed->images_.empty()) { 400 parsed->images_.push_back("/system/framework/boot.art"); 401 } 402 if (parsed->heap_growth_limit_ == 0) { 403 parsed->heap_growth_limit_ = parsed->heap_maximum_size_; 404 } 405 406 LOG(INFO) << "Build type: " 407#ifndef NDEBUG 408 << "debug" 409#else 410 << "optimized" 411#endif 412 << "; CheckJNI: " << (parsed->check_jni_ ? "on" : "off"); 413 414 return parsed.release(); 415} 416 417Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) { 418 // TODO: acquire a static mutex on Runtime to avoid racing. 419 if (Runtime::instance_ != NULL) { 420 return NULL; 421 } 422 instance_ = new Runtime; 423 if (!instance_->Init(options, ignore_unrecognized)) { 424 delete instance_; 425 instance_ = NULL; 426 } 427 return instance_; 428} 429 430void CreateSystemClassLoader() { 431 if (ClassLoader::UseCompileTimeClassPath()) { 432 return; 433 } 434 435 Thread* self = Thread::Current(); 436 437 // Must be in the kNative state for calling native methods. 438 CHECK_EQ(self->GetState(), Thread::kNative); 439 440 JNIEnv* env = self->GetJniEnv(); 441 ScopedLocalRef<jclass> ClassLoader_class(env, env->FindClass("java/lang/ClassLoader")); 442 CHECK(ClassLoader_class.get() != NULL); 443 jmethodID getSystemClassLoader = env->GetStaticMethodID(ClassLoader_class.get(), 444 "getSystemClassLoader", 445 "()Ljava/lang/ClassLoader;"); 446 CHECK(getSystemClassLoader != NULL); 447 ScopedLocalRef<jobject> class_loader(env, env->CallStaticObjectMethod(ClassLoader_class.get(), 448 getSystemClassLoader)); 449 CHECK(class_loader.get() != NULL); 450 451 Thread::Current()->SetClassLoaderOverride(Decode<ClassLoader*>(env, class_loader.get())); 452 453 ScopedLocalRef<jclass> Thread_class(env, env->FindClass("java/lang/Thread")); 454 CHECK(Thread_class.get() != NULL); 455 jfieldID contextClassLoader = env->GetFieldID(Thread_class.get(), 456 "contextClassLoader", 457 "Ljava/lang/ClassLoader;"); 458 CHECK(contextClassLoader != NULL); 459 ScopedLocalRef<jobject> self_jobject(env, AddLocalReference<jobject>(env, self->GetPeer())); 460 env->SetObjectField(self_jobject.get(), contextClassLoader, class_loader.get()); 461} 462 463void Runtime::Start() { 464 VLOG(startup) << "Runtime::Start entering"; 465 466 CHECK(host_prefix_.empty()) << host_prefix_; 467 468 // Restore main thread state to kNative as expected by native code 469 Thread::Current()->SetState(Thread::kNative); 470 471 started_ = true; 472 473 // InitNativeMethods needs to be after started_ so that the classes 474 // it touches will have methods linked to the oat file if necessary. 475 InitNativeMethods(); 476 477 Thread::FinishStartup(); 478 479 if (!is_zygote_) { 480 DidForkFromZygote(); 481 } 482 483 StartDaemonThreads(); 484 485 CreateSystemClassLoader(); 486 487 Thread::Current()->GetJniEnv()->locals.AssertEmpty(); 488 489 VLOG(startup) << "Runtime::Start exiting"; 490} 491 492void Runtime::DidForkFromZygote() { 493 is_zygote_ = false; 494 495 StartSignalCatcher(); 496 497 // Start the JDWP thread. If the command-line debugger flags specified "suspend=y", 498 // this will pause the runtime, so we probably want this to come last. 499 Dbg::StartJdwp(); 500} 501 502void Runtime::StartSignalCatcher() { 503 if (!is_zygote_) { 504 signal_catcher_ = new SignalCatcher(stack_trace_file_); 505 } 506} 507 508void Runtime::StartDaemonThreads() { 509 VLOG(startup) << "Runtime::StartDaemonThreads entering"; 510 511 Thread* self = Thread::Current(); 512 513 // Must be in the kNative state for calling native methods. 514 CHECK_EQ(self->GetState(), Thread::kNative); 515 516 JNIEnv* env = self->GetJniEnv(); 517 ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Daemons")); 518 CHECK(c.get() != NULL); 519 jmethodID mid = env->GetStaticMethodID(c.get(), "start", "()V"); 520 CHECK(mid != NULL); 521 env->CallStaticVoidMethod(c.get(), mid); 522 523 VLOG(startup) << "Runtime::StartDaemonThreads exiting"; 524} 525 526bool Runtime::IsStarted() const { 527 return started_; 528} 529 530bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { 531 CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); 532 533 UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized)); 534 if (options.get() == NULL) { 535 LOG(ERROR) << "Failed to parse options"; 536 return false; 537 } 538 VLOG(startup) << "Runtime::Init -verbose:startup enabled"; 539 540 SetJniGlobalsMax(options->jni_globals_max_); 541 Monitor::Init(options->lock_profiling_threshold_, options->hook_is_sensitive_thread_); 542 543 host_prefix_ = options->host_prefix_; 544 boot_class_path_ = options->boot_class_path_; 545 class_path_ = options->class_path_; 546 properties_ = options->properties_; 547 548 is_zygote_ = options->is_zygote_; 549 550 vfprintf_ = options->hook_vfprintf_; 551 exit_ = options->hook_exit_; 552 abort_ = options->hook_abort_; 553 554 default_stack_size_ = options->stack_size_; 555 stack_trace_file_ = options->stack_trace_file_; 556 557 monitor_list_ = new MonitorList; 558 thread_list_ = new ThreadList; 559 intern_table_ = new InternTable; 560 561 Heap::Init(options->heap_initial_size_, 562 options->heap_maximum_size_, 563 options->heap_growth_limit_, 564 options->images_); 565 566 BlockSignals(); 567 568 java_vm_ = new JavaVMExt(this, options.get()); 569 570 Thread::Startup(); 571 572 // ClassLinker needs an attached thread, but we can't fully attach a thread 573 // without creating objects. 574 Thread::Attach(this, "main", false); 575 576 // Set us to runnable so tools using a runtime can allocate and GC by default 577 Thread::Current()->SetState(Thread::kRunnable); 578 579 CHECK_GE(Heap::GetSpaces().size(), 1U); 580 class_linker_ = ((Heap::GetSpaces()[0]->IsImageSpace()) 581 ? ClassLinker::Create(intern_table_) 582 : ClassLinker::Create(options->boot_class_path_, intern_table_)); 583 584 VLOG(startup) << "Runtime::Init exiting"; 585 return true; 586} 587 588void Runtime::InitNativeMethods() { 589 VLOG(startup) << "Runtime::InitNativeMethods entering"; 590 Thread* self = Thread::Current(); 591 JNIEnv* env = self->GetJniEnv(); 592 593 // Must be in the kNative state for calling native methods (JNI_OnLoad code). 594 CHECK_EQ(self->GetState(), Thread::kNative); 595 596 // First set up JniConstants, which is used by both the runtime's built-in native 597 // methods and libcore. 598 JniConstants::init(env); 599 600 // Then set up the native methods provided by the runtime itself. 601 RegisterRuntimeNativeMethods(env); 602 603 // Then set up libcore, which is just a regular JNI library with a regular JNI_OnLoad. 604 // Most JNI libraries can just use System.loadLibrary, but libcore can't because it's 605 // the library that implements System.loadLibrary! 606 LoadJniLibrary(instance_->GetJavaVM(), "javacore"); 607 VLOG(startup) << "Runtime::InitNativeMethods exiting"; 608} 609 610void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { 611#define REGISTER(FN) extern void FN(JNIEnv*); FN(env) 612 REGISTER(register_dalvik_system_DexFile); 613 REGISTER(register_dalvik_system_VMDebug); 614 REGISTER(register_dalvik_system_VMRuntime); 615 REGISTER(register_dalvik_system_VMStack); 616 REGISTER(register_dalvik_system_Zygote); 617 REGISTER(register_java_lang_Class); 618 REGISTER(register_java_lang_Object); 619 REGISTER(register_java_lang_Runtime); 620 REGISTER(register_java_lang_String); 621 REGISTER(register_java_lang_System); 622 REGISTER(register_java_lang_Thread); 623 REGISTER(register_java_lang_Throwable); 624 REGISTER(register_java_lang_VMClassLoader); 625 REGISTER(register_java_lang_reflect_Array); 626 REGISTER(register_java_lang_reflect_Constructor); 627 REGISTER(register_java_lang_reflect_Field); 628 REGISTER(register_java_lang_reflect_Method); 629 REGISTER(register_java_lang_reflect_Proxy); 630 REGISTER(register_java_util_concurrent_atomic_AtomicLong); 631 REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmServer); 632 REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmVmInternal); 633 REGISTER(register_sun_misc_Unsafe); 634#undef REGISTER 635} 636 637void Runtime::Dump(std::ostream& os) { 638 // TODO: dump other runtime statistics? 639 GetClassLinker()->DumpForSigQuit(os); 640 GetInternTable()->DumpForSigQuit(os); 641 os << "\n"; 642 643 thread_list_->Dump(os); 644} 645 646void Runtime::DumpLockHolders(std::ostream& os) { 647 pid_t heap_lock_owner = Heap::GetLockOwner(); 648 pid_t thread_list_lock_owner = GetThreadList()->GetLockOwner(); 649 pid_t classes_lock_owner = GetClassLinker()->GetClassesLockOwner(); 650 pid_t dex_lock_owner = GetClassLinker()->GetDexLockOwner(); 651 if ((heap_lock_owner | thread_list_lock_owner | classes_lock_owner | dex_lock_owner) != 0) { 652 os << "Heap lock owner tid: " << heap_lock_owner << "\n" 653 << "ThreadList lock owner tid: " << thread_list_lock_owner << "\n" 654 << "ClassLinker classes lock owner tid: " << classes_lock_owner << "\n" 655 << "ClassLinker dex lock owner tid: " << dex_lock_owner << "\n"; 656 } 657} 658 659void Runtime::SetStatsEnabled(bool new_state) { 660 if (new_state == true) { 661 GetStats()->Clear(~0); 662 // TODO: wouldn't it make more sense to clear _all_ threads' stats? 663 Thread::Current()->GetStats()->Clear(~0); 664 } 665 stats_enabled_ = new_state; 666} 667 668void Runtime::ResetStats(int kinds) { 669 GetStats()->Clear(kinds & 0xffff); 670 // TODO: wouldn't it make more sense to clear _all_ threads' stats? 671 Thread::Current()->GetStats()->Clear(kinds >> 16); 672} 673 674RuntimeStats* Runtime::GetStats() { 675 return &stats_; 676} 677 678int32_t Runtime::GetStat(int kind) { 679 RuntimeStats* stats; 680 if (kind < (1<<16)) { 681 stats = GetStats(); 682 } else { 683 stats = Thread::Current()->GetStats(); 684 kind >>= 16; 685 } 686 switch (kind) { 687 case KIND_ALLOCATED_OBJECTS: 688 return stats->allocated_objects; 689 case KIND_ALLOCATED_BYTES: 690 return stats->allocated_bytes; 691 case KIND_FREED_OBJECTS: 692 return stats->freed_objects; 693 case KIND_FREED_BYTES: 694 return stats->freed_bytes; 695 case KIND_GC_INVOCATIONS: 696 return stats->gc_for_alloc_count; 697 case KIND_CLASS_INIT_COUNT: 698 return stats->class_init_count; 699 case KIND_CLASS_INIT_TIME: 700 // Convert ns to us, reduce to 32 bits. 701 return (int) (stats->class_init_time_ns / 1000); 702 case KIND_EXT_ALLOCATED_OBJECTS: 703 case KIND_EXT_ALLOCATED_BYTES: 704 case KIND_EXT_FREED_OBJECTS: 705 case KIND_EXT_FREED_BYTES: 706 return 0; // backward compatibility 707 default: 708 CHECK(false); 709 return -1; // unreachable 710 } 711} 712 713void Runtime::BlockSignals() { 714 sigset_t sigset; 715 if (sigemptyset(&sigset) == -1) { 716 PLOG(FATAL) << "sigemptyset failed"; 717 } 718 if (sigaddset(&sigset, SIGPIPE) == -1) { 719 PLOG(ERROR) << "sigaddset SIGPIPE failed"; 720 } 721 // SIGQUIT is used to dump the runtime's state (including stack traces). 722 if (sigaddset(&sigset, SIGQUIT) == -1) { 723 PLOG(ERROR) << "sigaddset SIGQUIT failed"; 724 } 725 // SIGUSR1 is used to initiate a heap dump. 726 if (sigaddset(&sigset, SIGUSR1) == -1) { 727 PLOG(ERROR) << "sigaddset SIGUSR1 failed"; 728 } 729 CHECK_EQ(sigprocmask(SIG_BLOCK, &sigset, NULL), 0); 730} 731 732void Runtime::AttachCurrentThread(const char* name, bool as_daemon) { 733 Thread::Attach(instance_, name, as_daemon); 734} 735 736void Runtime::DetachCurrentThread() { 737 // TODO: check we're not calling DetachCurrentThread from a call stack that 738 // includes managed frames. (It's only valid if the stack is all-native.) 739 thread_list_->Unregister(); 740} 741 742void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const { 743 Dbg::VisitRoots(visitor, arg); 744 class_linker_->VisitRoots(visitor, arg); 745 intern_table_->VisitRoots(visitor, arg); 746 java_vm_->VisitRoots(visitor, arg); 747 thread_list_->VisitRoots(visitor, arg); 748 visitor(jni_stub_array_, arg); 749 visitor(abstract_method_error_stub_array_, arg); 750 for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) { 751 visitor(resolution_stub_array_[i], arg); 752 } 753 for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { 754 visitor(callee_save_method_[i], arg); 755 } 756} 757 758bool Runtime::HasJniDlsymLookupStub() const { 759 return jni_stub_array_ != NULL; 760} 761 762ByteArray* Runtime::GetJniDlsymLookupStub() const { 763 CHECK(jni_stub_array_ != NULL); 764 return jni_stub_array_; 765} 766 767void Runtime::SetJniDlsymLookupStub(ByteArray* jni_stub_array) { 768 CHECK(jni_stub_array != NULL) << " jni_stub_array=" << jni_stub_array; 769 CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array) 770 << "jni_stub_array_=" << jni_stub_array_ << " jni_stub_array=" << jni_stub_array; 771 jni_stub_array_ = jni_stub_array; 772} 773 774bool Runtime::HasAbstractMethodErrorStubArray() const { 775 return abstract_method_error_stub_array_ != NULL; 776} 777 778ByteArray* Runtime::GetAbstractMethodErrorStubArray() const { 779 CHECK(abstract_method_error_stub_array_ != NULL); 780 return abstract_method_error_stub_array_; 781} 782 783void Runtime::SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array) { 784 CHECK(abstract_method_error_stub_array != NULL); 785 CHECK(abstract_method_error_stub_array_ == NULL || abstract_method_error_stub_array_ == abstract_method_error_stub_array); 786 abstract_method_error_stub_array_ = abstract_method_error_stub_array; 787} 788 789 790Runtime::TrampolineType Runtime::GetTrampolineType(Method* method) { 791 if (method == NULL) { 792 return Runtime::kUnknownMethod; 793 } else if (method->IsStatic()) { 794 return Runtime::kStaticMethod; 795 } else { 796 return Runtime::kInstanceMethod; 797 } 798} 799 800bool Runtime::HasResolutionStubArray(TrampolineType type) const { 801 return resolution_stub_array_[type] != NULL; 802} 803 804ByteArray* Runtime::GetResolutionStubArray(TrampolineType type) const { 805 CHECK(HasResolutionStubArray(type)); 806 DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastTrampolineMethodType)); 807 return resolution_stub_array_[type]; 808} 809 810void Runtime::SetResolutionStubArray(ByteArray* resolution_stub_array, TrampolineType type) { 811 CHECK(resolution_stub_array != NULL); 812 CHECK(!HasResolutionStubArray(type) || resolution_stub_array_[type] == resolution_stub_array); 813 resolution_stub_array_[type] = resolution_stub_array; 814} 815 816Method* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type) { 817 Class* method_class = Method::GetMethodClass(); 818 SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject())); 819 method->SetDeclaringClass(method_class); 820 // TODO: use a special method for callee saves 821 method->SetMethodIndex(DexFile::kDexNoIndex16); 822 method->SetCode(NULL); 823 if ((instruction_set == kThumb2) || (instruction_set == kArm)) { 824 uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) | 825 (1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11); 826 uint32_t arg_spills = (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3); 827 uint32_t all_spills = (1 << art::arm::R4) | (1 << art::arm::R9); 828 uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills :0) | 829 (type == kSaveAll ? all_spills :0) | (1 << art::arm::LR); 830 uint32_t fp_all_spills = (1 << art::arm::S0) | (1 << art::arm::S1) | (1 << art::arm::S2) | 831 (1 << art::arm::S3) | (1 << art::arm::S4) | (1 << art::arm::S5) | 832 (1 << art::arm::S6) | (1 << art::arm::S7) | (1 << art::arm::S8) | 833 (1 << art::arm::S9) | (1 << art::arm::S10) | (1 << art::arm::S11) | 834 (1 << art::arm::S12) | (1 << art::arm::S13) | (1 << art::arm::S14) | 835 (1 << art::arm::S15) | (1 << art::arm::S16) | (1 << art::arm::S17) | 836 (1 << art::arm::S18) | (1 << art::arm::S19) | (1 << art::arm::S20) | 837 (1 << art::arm::S21) | (1 << art::arm::S22) | (1 << art::arm::S23) | 838 (1 << art::arm::S24) | (1 << art::arm::S25) | (1 << art::arm::S26) | 839 (1 << art::arm::S27) | (1 << art::arm::S28) | (1 << art::arm::S29) | 840 (1 << art::arm::S30) | (1 << art::arm::S31); 841 uint32_t fp_spills = type == kSaveAll ? fp_all_spills : 0; 842 size_t frame_size = RoundUp((__builtin_popcount(core_spills) /* gprs */ + 843 __builtin_popcount(fp_spills) /* fprs */ + 844 1 /* Method* */) * kPointerSize, kStackAlignment); 845 method->SetFrameSizeInBytes(frame_size); 846 method->SetCoreSpillMask(core_spills); 847 method->SetFpSpillMask(fp_spills); 848 } else if (instruction_set == kX86) { 849 method->SetFrameSizeInBytes(32); 850 method->SetCoreSpillMask((1 << art::x86::EBX) | (1 << art::x86::EBP) | (1 << art::x86::ESI) | 851 (1 << art::x86::EDI)); 852 method->SetFpSpillMask(0); 853 } else { 854 UNIMPLEMENTED(FATAL); 855 } 856 return method.get(); 857} 858 859bool Runtime::HasCalleeSaveMethod(CalleeSaveType type) const { 860 return callee_save_method_[type] != NULL; 861} 862 863// Returns a special method that describes all callee saves being spilled to the stack. 864Method* Runtime::GetCalleeSaveMethod(CalleeSaveType type) const { 865 CHECK(HasCalleeSaveMethod(type)); 866 return callee_save_method_[type]; 867} 868 869void Runtime::SetCalleeSaveMethod(Method* method, CalleeSaveType type) { 870 DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastCalleeSaveType)); 871 callee_save_method_[type] = method; 872} 873 874void Runtime::EnableMethodTracing(Trace* tracer) { 875 CHECK(!IsMethodTracingActive()); 876 tracer_ = tracer; 877} 878 879void Runtime::DisableMethodTracing() { 880 CHECK(IsMethodTracingActive()); 881 delete tracer_; 882 tracer_ = NULL; 883} 884 885bool Runtime::IsMethodTracingActive() const { 886 return (tracer_ != NULL); 887} 888 889Trace* Runtime::GetTracer() const { 890 CHECK(IsMethodTracingActive()); 891 return tracer_; 892} 893 894} // namespace art 895