blob: e628f2ce157b3ced4d9507246f045e606a3acd9a [file] [log] [blame]
Carl Shapiro1fb86202011-06-27 17:43:13 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "runtime.h"
Carl Shapiro1fb86202011-06-27 17:43:13 -07004
Elliott Hughesffe67362011-07-17 12:09:27 -07005#include <cstdio>
6#include <cstdlib>
Brian Carlstrom8a436592011-08-15 21:27:23 -07007#include <limits>
Carl Shapiro2ed144c2011-07-26 16:52:08 -07008#include <vector>
Elliott Hughesffe67362011-07-17 12:09:27 -07009
Elliott Hughes18c07532011-08-18 15:50:51 -070010#include "JniConstants.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070011#include "class_linker.h"
12#include "heap.h"
Elliott Hughesc5f7c912011-08-18 14:00:42 -070013#include "jni_internal.h"
Carl Shapirofc322c72011-07-27 00:20:01 -070014#include "scoped_ptr.h"
Elliott Hughese27955c2011-08-26 15:21:24 -070015#include "signal_catcher.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070016#include "thread.h"
Carl Shapiro61e019d2011-07-14 16:53:09 -070017
Carl Shapiro1fb86202011-06-27 17:43:13 -070018namespace art {
19
Carl Shapiro2ed144c2011-07-26 16:52:08 -070020Runtime* Runtime::instance_ = NULL;
21
Carl Shapiro61e019d2011-07-14 16:53:09 -070022Runtime::~Runtime() {
Elliott Hughesc5f7c912011-08-18 14:00:42 -070023 // TODO: use smart pointers instead. (we'll need the pimpl idiom.)
Carl Shapiro61e019d2011-07-14 16:53:09 -070024 delete class_linker_;
Carl Shapiro69759ea2011-07-21 18:13:35 -070025 Heap::Destroy();
Elliott Hughese27955c2011-08-26 15:21:24 -070026 delete signal_catcher_;
Carl Shapiro61e019d2011-07-14 16:53:09 -070027 delete thread_list_;
Elliott Hughesc5f7c912011-08-18 14:00:42 -070028 delete java_vm_;
Elliott Hughesc1674ed2011-08-25 18:09:09 -070029 Thread::Shutdown();
Carl Shapiro4acf4642011-07-26 18:54:13 -070030 // TODO: acquire a static mutex on Runtime to avoid racing.
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070031 CHECK(instance_ == NULL || instance_ == this);
Carl Shapiro4acf4642011-07-26 18:54:13 -070032 instance_ = NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -070033}
34
Elliott Hughesffe67362011-07-17 12:09:27 -070035void Runtime::Abort(const char* file, int line) {
36 // Get any pending output out of the way.
37 fflush(NULL);
38
39 // Many people have difficulty distinguish aborts from crashes,
40 // so be explicit.
41 LogMessage(file, line, ERROR, -1).stream() << "Runtime aborting...";
42
Elliott Hughesffe67362011-07-17 12:09:27 -070043 // Perform any platform-specific pre-abort actions.
44 PlatformAbort(file, line);
45
Brian Carlstrom6ea095a2011-08-16 15:26:54 -070046 // use abort hook if we have one
47 if (Runtime::Current() != NULL && Runtime::Current()->abort_ != NULL) {
48 Runtime::Current()->abort_();
49 // notreached
50 }
51
Elliott Hughesffe67362011-07-17 12:09:27 -070052 // If we call abort(3) on a device, all threads in the process
Carl Shapiro69759ea2011-07-21 18:13:35 -070053 // receive SIGABRT. debuggerd dumps the stack trace of the main
54 // thread, whether or not that was the thread that failed. By
55 // stuffing a value into a bogus address, we cause a segmentation
Elliott Hughesffe67362011-07-17 12:09:27 -070056 // fault in the current thread, and get a useful log from debuggerd.
57 // We can also trivially tell the difference between a VM crash and
58 // a deliberate abort by looking at the fault address.
59 *reinterpret_cast<char*>(0xdeadd00d) = 38;
60 abort();
Elliott Hughesffe67362011-07-17 12:09:27 -070061 // notreached
62}
63
Brian Carlstrom8a436592011-08-15 21:27:23 -070064// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
65// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
66// [gG] gigabytes.
67//
68// "s" should point just past the "-Xm?" part of the string.
Brian Carlstrom8a436592011-08-15 21:27:23 -070069// "div" specifies a divisor, e.g. 1024 if the value must be a multiple
70// of 1024.
71//
72// The spec says the -Xmx and -Xms options must be multiples of 1024. It
73// doesn't say anything about -Xss.
74//
75// Returns 0 (a useless size) if "s" is malformed or specifies a low or
76// non-evenly-divisible value.
77//
78size_t ParseMemoryOption(const char *s, size_t div) {
79 // strtoul accepts a leading [+-], which we don't want,
80 // so make sure our string starts with a decimal digit.
81 if (isdigit(*s)) {
82 const char *s2;
83 size_t val = strtoul(s, (char **)&s2, 10);
84 if (s2 != s) {
85 // s2 should be pointing just after the number.
86 // If this is the end of the string, the user
87 // has specified a number of bytes. Otherwise,
88 // there should be exactly one more character
89 // that specifies a multiplier.
90 if (*s2 != '\0') {
Brian Carlstromf734cf52011-08-17 16:28:14 -070091 // The remainder of the string is either a single multiplier
92 // character, or nothing to indicate that the value is in
93 // bytes.
94 char c = *s2++;
95 if (*s2 == '\0') {
96 size_t mul;
97 if (c == '\0') {
98 mul = 1;
99 } else if (c == 'k' || c == 'K') {
100 mul = KB;
101 } else if (c == 'm' || c == 'M') {
102 mul = MB;
103 } else if (c == 'g' || c == 'G') {
104 mul = GB;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700105 } else {
Brian Carlstromf734cf52011-08-17 16:28:14 -0700106 // Unknown multiplier character.
Brian Carlstrom8a436592011-08-15 21:27:23 -0700107 return 0;
108 }
Brian Carlstromf734cf52011-08-17 16:28:14 -0700109
110 if (val <= std::numeric_limits<size_t>::max() / mul) {
111 val *= mul;
112 } else {
113 // Clamp to a multiple of 1024.
114 val = std::numeric_limits<size_t>::max() & ~(1024-1);
115 }
116 } else {
117 // There's more than one character after the numeric part.
118 return 0;
119 }
Brian Carlstrom8a436592011-08-15 21:27:23 -0700120 }
121 // The man page says that a -Xm value must be a multiple of 1024.
122 if (val % div == 0) {
123 return val;
124 }
Carl Shapirofc322c72011-07-27 00:20:01 -0700125 }
126 }
Brian Carlstrom8a436592011-08-15 21:27:23 -0700127 return 0;
Carl Shapirofc322c72011-07-27 00:20:01 -0700128}
129
Elliott Hughes0af55432011-08-17 18:37:28 -0700130void LoadJniLibrary(JavaVMExt* vm, const char* name) {
131 // TODO: OS_SHARED_LIB_FORMAT_STR
132 std::string mapped_name(StringPrintf("lib%s.so", name));
Elliott Hughes75770752011-08-24 17:52:38 -0700133 std::string reason;
134 if (!vm->LoadNativeLibrary(mapped_name, NULL, reason)) {
Elliott Hughes0af55432011-08-17 18:37:28 -0700135 LOG(FATAL) << "LoadNativeLibrary failed for \"" << mapped_name << "\": "
136 << reason;
137 }
138}
139
Brian Carlstrom9f30b382011-08-28 22:41:38 -0700140const DexFile* Open(const std::string& filename) {
Elliott Hughes40ef99e2011-08-11 17:44:34 -0700141 if (filename.size() < 4) {
142 LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'";
143 return NULL;
144 }
145 std::string suffix(filename.substr(filename.size() - 4));
146 if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") {
147 return DexFile::OpenZip(filename);
148 } else {
149 return DexFile::OpenFile(filename);
150 }
151}
152
Brian Carlstrom8a436592011-08-15 21:27:23 -0700153void CreateBootClassPath(const char* boot_class_path_cstr,
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -0700154 std::vector<const DexFile*>& boot_class_path_vector) {
Brian Carlstrom8a436592011-08-15 21:27:23 -0700155 CHECK(boot_class_path_cstr != NULL);
Carl Shapirofc322c72011-07-27 00:20:01 -0700156 std::vector<std::string> parsed;
Elliott Hughes34023802011-08-30 12:06:17 -0700157 Split(boot_class_path_cstr, ':', parsed);
Carl Shapirofc322c72011-07-27 00:20:01 -0700158 for (size_t i = 0; i < parsed.size(); ++i) {
Brian Carlstrom9f30b382011-08-28 22:41:38 -0700159 const DexFile* dex_file = Open(parsed[i]);
Carl Shapirofc322c72011-07-27 00:20:01 -0700160 if (dex_file != NULL) {
Brian Carlstrom8a436592011-08-15 21:27:23 -0700161 boot_class_path_vector.push_back(dex_file);
Carl Shapirofc322c72011-07-27 00:20:01 -0700162 }
163 }
164}
165
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700166Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) {
167 scoped_ptr<ParsedOptions> parsed(new ParsedOptions());
Brian Carlstrom8a436592011-08-15 21:27:23 -0700168 const char* boot_class_path = getenv("BOOTCLASSPATH");
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700169 parsed->boot_image_ = NULL;
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700170#ifdef NDEBUG
Elliott Hughes5174fe62011-08-23 15:12:35 -0700171 // -Xcheck:jni is off by default for regular builds...
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700172 parsed->check_jni_ = false;
173#else
174 // ...but on by default in debug builds.
175 parsed->check_jni_ = true;
176#endif
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700177 parsed->heap_initial_size_ = Heap::kInitialSize;
178 parsed->heap_maximum_size_ = Heap::kMaximumSize;
Brian Carlstromf734cf52011-08-17 16:28:14 -0700179 parsed->stack_size_ = Thread::kDefaultStackSize;
180
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700181 parsed->hook_vfprintf_ = vfprintf;
182 parsed->hook_exit_ = exit;
183 parsed->hook_abort_ = abort;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700184
185 for (size_t i = 0; i < options.size(); ++i) {
186 const StringPiece& option = options[i].first;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700187 if (option.starts_with("-Xbootclasspath:")) {
188 boot_class_path = option.substr(strlen("-Xbootclasspath:")).data();
189 } else if (option == "bootclasspath") {
Brian Carlstromf734cf52011-08-17 16:28:14 -0700190 const void* dex_vector = options[i].second;
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -0700191 const std::vector<const DexFile*>* v
192 = reinterpret_cast<const std::vector<const DexFile*>*>(dex_vector);
Brian Carlstromf734cf52011-08-17 16:28:14 -0700193 if (v == NULL) {
194 if (ignore_unrecognized) {
195 continue;
196 }
197 // TODO: usage
198 LOG(FATAL) << "Could not parse " << option;
199 return NULL;
200 }
201 parsed->boot_class_path_ = *v;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700202 } else if (option.starts_with("-Xbootimage:")) {
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700203 parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700204 } else if (option.starts_with("-Xcheck:jni")) {
205 parsed->check_jni_ = true;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700206 } else if (option.starts_with("-Xms")) {
Brian Carlstromf734cf52011-08-17 16:28:14 -0700207 size_t size = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
208 if (size == 0) {
209 if (ignore_unrecognized) {
210 continue;
211 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700212 // TODO: usage
Brian Carlstromf734cf52011-08-17 16:28:14 -0700213 LOG(FATAL) << "Could not parse " << option;
214 return NULL;
215 }
216 parsed->heap_initial_size_ = size;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700217 } else if (option.starts_with("-Xmx")) {
Brian Carlstromf734cf52011-08-17 16:28:14 -0700218 size_t size = ParseMemoryOption(option.substr(strlen("-Xmx")).data(), 1024);
219 if (size == 0) {
220 if (ignore_unrecognized) {
221 continue;
222 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700223 // TODO: usage
Brian Carlstromf734cf52011-08-17 16:28:14 -0700224 LOG(FATAL) << "Could not parse " << option;
225 return NULL;
226 }
227 parsed->heap_maximum_size_ = size;
228 } else if (option.starts_with("-Xss")) {
229 size_t size = ParseMemoryOption(option.substr(strlen("-Xss")).data(), 1);
230 if (size == 0) {
231 if (ignore_unrecognized) {
232 continue;
233 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700234 // TODO: usage
Brian Carlstromf734cf52011-08-17 16:28:14 -0700235 LOG(FATAL) << "Could not parse " << option;
236 return NULL;
237 }
238 parsed->stack_size_ = size;
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700239 } else if (option.starts_with("-D")) {
240 parsed->properties_.push_back(option.substr(strlen("-D")).data());
241 } else if (option.starts_with("-verbose:")) {
Elliott Hughes0af55432011-08-17 18:37:28 -0700242 std::vector<std::string> verbose_options;
Elliott Hughes34023802011-08-30 12:06:17 -0700243 Split(option.substr(strlen("-verbose:")).data(), ',', verbose_options);
Elliott Hughes0af55432011-08-17 18:37:28 -0700244 for (size_t i = 0; i < verbose_options.size(); ++i) {
245 parsed->verbose_.insert(verbose_options[i]);
246 }
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700247 } else if (option == "vfprintf") {
248 parsed->hook_vfprintf_ = reinterpret_cast<int (*)(FILE *, const char*, va_list)>(options[i].second);
249 } else if (option == "exit") {
250 parsed->hook_exit_ = reinterpret_cast<void(*)(jint)>(options[i].second);
251 } else if (option == "abort") {
252 parsed->hook_abort_ = reinterpret_cast<void(*)()>(options[i].second);
Brian Carlstrom8a436592011-08-15 21:27:23 -0700253 } else {
254 if (!ignore_unrecognized) {
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700255 // TODO: print usage via vfprintf
Brian Carlstrom8a436592011-08-15 21:27:23 -0700256 LOG(FATAL) << "Unrecognized option " << option;
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700257 return NULL;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700258 }
259 }
260 }
261
262 if (boot_class_path == NULL) {
263 boot_class_path = "";
264 }
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700265 if (parsed->boot_class_path_.size() == 0) {
266 CreateBootClassPath(boot_class_path, parsed->boot_class_path_);
Brian Carlstrom8a436592011-08-15 21:27:23 -0700267 }
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700268 return parsed.release();
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700269}
270
Brian Carlstrom8a436592011-08-15 21:27:23 -0700271Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) {
272 Runtime::Options options;
273 options.push_back(std::make_pair("bootclasspath", &boot_class_path));
274 return Runtime::Create(options, false);
275}
276
277Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700278 // TODO: acquire a static mutex on Runtime to avoid racing.
279 if (Runtime::instance_ != NULL) {
280 return NULL;
281 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700282 scoped_ptr<Runtime> runtime(new Runtime());
Brian Carlstrom8a436592011-08-15 21:27:23 -0700283 bool success = runtime->Init(options, ignore_unrecognized);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700284 if (!success) {
285 return NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700286 }
Elliott Hughes0af55432011-08-17 18:37:28 -0700287 instance_ = runtime.release();
288
289 // Most JNI libraries can just use System.loadLibrary, but you can't
290 // if you're the library that implements System.loadLibrary!
Elliott Hughes18c07532011-08-18 15:50:51 -0700291 Thread* self = Thread::Current();
292 Thread::State old_state = self->GetState();
293 self->SetState(Thread::kNative);
294 JniConstants::init(self->GetJniEnv());
Elliott Hughes0af55432011-08-17 18:37:28 -0700295 LoadJniLibrary(instance_->GetJavaVM(), "javacore");
Elliott Hughes18c07532011-08-18 15:50:51 -0700296 self->SetState(old_state);
Elliott Hughes0af55432011-08-17 18:37:28 -0700297
Elliott Hughese27955c2011-08-26 15:21:24 -0700298 instance_->signal_catcher_ = new SignalCatcher;
299
Elliott Hughes0af55432011-08-17 18:37:28 -0700300 return instance_;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700301}
302
Elliott Hughes0af55432011-08-17 18:37:28 -0700303bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700304 CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700305
Elliott Hughes0af55432011-08-17 18:37:28 -0700306 scoped_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
307 if (options == NULL) {
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700308 return false;
309 }
Elliott Hughes0af55432011-08-17 18:37:28 -0700310 vfprintf_ = options->hook_vfprintf_;
311 exit_ = options->hook_exit_;
312 abort_ = options->hook_abort_;
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700313
Brian Carlstromb765be02011-08-17 23:54:10 -0700314 stack_size_ = options->stack_size_;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700315 thread_list_ = ThreadList::Create();
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700316
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700317 if (!Heap::Init(options->heap_initial_size_,
318 options->heap_maximum_size_,
319 options->boot_image_)) {
320 return false;
321 }
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700322
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700323 BlockSignals();
324
Elliott Hughes0af55432011-08-17 18:37:28 -0700325 bool verbose_jni = options->verbose_.find("jni") != options->verbose_.end();
Elliott Hughesc5f7c912011-08-18 14:00:42 -0700326 java_vm_ = new JavaVMExt(this, options->check_jni_, verbose_jni);
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700327
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700328 if (!Thread::Startup()) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700329 return false;
330 }
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700331 Thread* current_thread = Thread::Attach(this);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700332 thread_list_->Register(current_thread);
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700333
Brian Carlstroma663ea52011-08-19 23:33:41 -0700334 class_linker_ = ClassLinker::Create(options->boot_class_path_, Heap::GetBootSpace());
Brian Carlstrom6ea095a2011-08-16 15:26:54 -0700335
Carl Shapiro1fb86202011-06-27 17:43:13 -0700336 return true;
337}
338
Elliott Hughese27955c2011-08-26 15:21:24 -0700339void Runtime::DumpStatistics(std::ostream& os) {
340 // TODO: dump other runtime statistics?
341 os << "Loaded classes: " << class_linker_->NumLoadedClasses() << "\n";
342 os << "Intern table size: " << class_linker_->GetInternTable().Size() << "\n";
343 // LOGV("VM stats: meth=%d ifld=%d sfld=%d linear=%d",
344 // gDvm.numDeclaredMethods,
345 // gDvm.numDeclaredInstFields,
346 // gDvm.numDeclaredStaticFields,
347 // gDvm.pBootLoaderAlloc->curOffset);
348 // LOGI("GC precise methods: %d", dvmPointerSetGetCount(gDvm.preciseMethods));
349}
350
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700351void Runtime::BlockSignals() {
352 sigset_t sigset;
353 if (sigemptyset(&sigset) == -1) {
354 PLOG(FATAL) << "sigemptyset failed";
355 }
356 if (sigaddset(&sigset, SIGPIPE) == -1) {
357 PLOG(ERROR) << "sigaddset SIGPIPE failed";
358 }
359 // SIGQUIT is used to dump the runtime's state (including stack traces).
360 if (sigaddset(&sigset, SIGQUIT) == -1) {
361 PLOG(ERROR) << "sigaddset SIGQUIT failed";
362 }
363 // SIGUSR1 is used to initiate a heap dump.
364 if (sigaddset(&sigset, SIGUSR1) == -1) {
365 PLOG(ERROR) << "sigaddset SIGUSR1 failed";
366 }
367 CHECK_EQ(sigprocmask(SIG_BLOCK, &sigset, NULL), 0);
368}
369
Elliott Hughes75770752011-08-24 17:52:38 -0700370bool Runtime::AttachCurrentThread(const char* name, JNIEnv** penv, bool as_daemon) {
371 if (as_daemon) {
372 UNIMPLEMENTED(WARNING) << "TODO: do something different for daemon threads";
373 }
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700374 return Thread::Attach(instance_) != NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700375}
376
Ian Rogersb033c752011-07-20 12:22:35 -0700377bool Runtime::DetachCurrentThread() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700378 Thread* self = Thread::Current();
379 thread_list_->Unregister(self);
380 delete self;
Ian Rogersb033c752011-07-20 12:22:35 -0700381 return true;
Carl Shapiro1fb86202011-06-27 17:43:13 -0700382}
383
384} // namespace art