Work on option parsing as prelude to image loading
Change-Id: I13edbd9b341e603817941beaca676535a7e590c7
diff --git a/src/runtime.cc b/src/runtime.cc
index 05a89b2..411ed67 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4,6 +4,7 @@
#include <cstdio>
#include <cstdlib>
+#include <limits>
#include <vector>
#include "class_linker.h"
@@ -72,21 +73,73 @@
}
}
-// TODO: move option processing elsewhere.
-const char* FindBootClassPath(const Runtime::Options& options) {
- const char* boot_class_path = getenv("BOOTCLASSPATH");
- const char* flag = "-Xbootclasspath:";
- for (size_t i = 0; i < options.size(); ++i) {
- const StringPiece& option = options[i].first;
- if (option.starts_with(flag)) {
- boot_class_path = option.substr(strlen(flag)).data();
+
+
+// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
+// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
+// [gG] gigabytes.
+//
+// "s" should point just past the "-Xm?" part of the string.
+// "min" specifies the lowest acceptable value described by "s".
+// "div" specifies a divisor, e.g. 1024 if the value must be a multiple
+// of 1024.
+//
+// The spec says the -Xmx and -Xms options must be multiples of 1024. It
+// doesn't say anything about -Xss.
+//
+// Returns 0 (a useless size) if "s" is malformed or specifies a low or
+// non-evenly-divisible value.
+//
+size_t ParseMemoryOption(const char *s, size_t div) {
+ // strtoul accepts a leading [+-], which we don't want,
+ // so make sure our string starts with a decimal digit.
+ if (isdigit(*s)) {
+ const char *s2;
+ size_t val = strtoul(s, (char **)&s2, 10);
+ if (s2 != s) {
+ // s2 should be pointing just after the number.
+ // If this is the end of the string, the user
+ // has specified a number of bytes. Otherwise,
+ // there should be exactly one more character
+ // that specifies a multiplier.
+ if (*s2 != '\0') {
+ // The remainder of the string is either a single multiplier
+ // character, or nothing to indicate that the value is in
+ // bytes.
+ char c = *s2++;
+ if (*s2 == '\0') {
+ size_t mul;
+ if (c == '\0') {
+ mul = 1;
+ } else if (c == 'k' || c == 'K') {
+ mul = 1024;
+ } else if (c == 'm' || c == 'M') {
+ mul = 1024 * 1024;
+ } else if (c == 'g' || c == 'G') {
+ mul = 1024 * 1024 * 1024;
+ } else {
+ // Unknown multiplier character.
+ return 0;
+ }
+
+ if (val <= std::numeric_limits<size_t>::max() / mul) {
+ val *= mul;
+ } else {
+ // Clamp to a multiple of 1024.
+ val = std::numeric_limits<size_t>::max() & ~(1024-1);
+ }
+ } else {
+ // There's more than one character after the numeric part.
+ return 0;
+ }
+ }
+ // The man page says that a -Xm value must be a multiple of 1024.
+ if (val % div == 0) {
+ return val;
+ }
}
}
- if (boot_class_path == NULL) {
- return "";
- } else {
- return boot_class_path;
- }
+ return 0;
}
DexFile* Open(const std::string& filename) {
@@ -102,35 +155,67 @@
}
}
-void CreateBootClassPath(const Runtime::Options& options,
- std::vector<DexFile*>* boot_class_path) {
- CHECK(boot_class_path != NULL);
- const char* str = FindBootClassPath(options);
+void CreateBootClassPath(const char* boot_class_path_cstr,
+ std::vector<DexFile*>& boot_class_path_vector) {
+ CHECK(boot_class_path_cstr != NULL);
std::vector<std::string> parsed;
- ParseClassPath(str, &parsed);
+ ParseClassPath(boot_class_path_cstr, &parsed);
for (size_t i = 0; i < parsed.size(); ++i) {
DexFile* dex_file = Open(parsed[i]);
if (dex_file != NULL) {
- boot_class_path->push_back(dex_file);
+ boot_class_path_vector.push_back(dex_file);
}
}
}
-// TODO: do something with ignore_unrecognized when we parse the option
-// strings for real.
-Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
- std::vector<DexFile*> boot_class_path;
- CreateBootClassPath(options, &boot_class_path);
- return Runtime::Create(boot_class_path);
+Runtime::ParsedOptions::ParsedOptions(const Options& options, bool ignore_unrecognized) {
+ const char* boot_class_path = getenv("BOOTCLASSPATH");
+ boot_image_ = NULL;
+ heap_initial_size_ = Heap::kInitialSize;
+ heap_maximum_size_ = Heap::kMaximumSize;
+
+ for (size_t i = 0; i < options.size(); ++i) {
+ const StringPiece& option = options[i].first;
+ // TODO parse -D, -verbose, vprintf, exit, abort
+ if (option.starts_with("-Xbootclasspath:")) {
+ boot_class_path = option.substr(strlen("-Xbootclasspath:")).data();
+ } else if (option == "bootclasspath") {
+ boot_class_path_ = *reinterpret_cast<const std::vector<DexFile*>*>(options[i].second);
+ } else if (option.starts_with("-Xbootimage:")) {
+ boot_image_ = option.substr(strlen("-Xbootimage:")).data();
+ } else if (option.starts_with("-Xms")) {
+ heap_initial_size_ = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
+ } else if (option.starts_with("-Xmx")) {
+ heap_maximum_size_ = ParseMemoryOption(option.substr(strlen("-Xmx")).data(), 1024);
+ } else {
+ if (!ignore_unrecognized) {
+ // TODO: indicate error for JNI_CreateJavaVM and print usage via vfprintf
+ LOG(FATAL) << "Unrecognized option " << option;
+ }
+ }
+ }
+
+ if (boot_class_path == NULL) {
+ boot_class_path = "";
+ }
+ if (boot_class_path_.size() == 0) {
+ CreateBootClassPath(boot_class_path, boot_class_path_);
+ }
}
-Runtime* Runtime::Create(const std::vector<DexFile*>& boot_class_path) {
+Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) {
+ Runtime::Options options;
+ options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+ return Runtime::Create(options, false);
+}
+
+Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
// TODO: acquire a static mutex on Runtime to avoid racing.
if (Runtime::instance_ != NULL) {
return NULL;
}
scoped_ptr<Runtime> runtime(new Runtime());
- bool success = runtime->Init(boot_class_path);
+ bool success = runtime->Init(options, ignore_unrecognized);
if (!success) {
return NULL;
} else {
@@ -138,14 +223,16 @@
}
}
-bool Runtime::Init(const std::vector<DexFile*>& boot_class_path) {
+bool Runtime::Init(const Options& options, bool ignore_unrecognized) {
+ ParsedOptions parsed_options(options, ignore_unrecognized);
CHECK_EQ(kPageSize, sysconf(_SC_PAGE_SIZE));
thread_list_ = ThreadList::Create();
- Heap::Init(Heap::kStartupSize, Heap::kMaximumSize);
+ Heap::Init(parsed_options.heap_initial_size_,
+ parsed_options.heap_maximum_size_);
Thread::Init();
Thread* current_thread = Thread::Attach();
thread_list_->Register(current_thread);
- class_linker_ = ClassLinker::Create(boot_class_path);
+ class_linker_ = ClassLinker::Create(parsed_options.boot_class_path_);
java_vm_.reset(CreateJavaVM(this));
return true;
}