Parse required options
Change-Id: Ia534132dcb1bfc4adbde3ed8afb07535e26ba942
diff --git a/src/runtime.cc b/src/runtime.cc
index 411ed67..2ad3589 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -34,11 +34,15 @@
// so be explicit.
LogMessage(file, line, ERROR, -1).stream() << "Runtime aborting...";
- // TODO: if we support an abort hook, call it here.
-
// Perform any platform-specific pre-abort actions.
PlatformAbort(file, line);
+ // use abort hook if we have one
+ if (Runtime::Current() != NULL && Runtime::Current()->abort_ != NULL) {
+ Runtime::Current()->abort_();
+ // notreached
+ }
+
// If we call abort(3) on a device, all threads in the process
// receive SIGABRT. debuggerd dumps the stack trace of the main
// thread, whether or not that was the thread that failed. By
@@ -48,24 +52,24 @@
// a deliberate abort by looking at the fault address.
*reinterpret_cast<char*>(0xdeadd00d) = 38;
abort();
-
// notreached
}
-// Splits a colon delimited list of pathname elements into a vector of
-// strings. Empty strings will be omitted.
-void ParseClassPath(const char* class_path, std::vector<std::string>* vec) {
- CHECK(vec != NULL);
- scoped_ptr_malloc<char> tmp(strdup(class_path));
+// Splits a C string using the given delimiter characters into a vector of
+// strings. Empty strings will be omitted.
+void Split(const char* str, const char* delim, std::vector<std::string>& vec) {
+ DCHECK(str != NULL);
+ DCHECK(delim != NULL);
+ scoped_ptr_malloc<char> tmp(strdup(str));
char* full = tmp.get();
char* p = full;
while (p != NULL) {
- p = strpbrk(full, ":");
+ p = strpbrk(full, delim);
if (p != NULL) {
p[0] = '\0';
}
if (full[0] != '\0') {
- vec->push_back(std::string(full));
+ vec.push_back(std::string(full));
}
if (p != NULL) {
full = p + 1;
@@ -73,7 +77,11 @@
}
}
-
+// Splits a colon delimited list of pathname elements into a vector of
+// strings. Empty strings will be omitted.
+void ParseClassPath(const char* class_path, std::vector<std::string>& vec) {
+ Split(class_path, ":", vec);
+}
// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
@@ -159,7 +167,7 @@
std::vector<DexFile*>& boot_class_path_vector) {
CHECK(boot_class_path_cstr != NULL);
std::vector<std::string> parsed;
- ParseClassPath(boot_class_path_cstr, &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) {
@@ -168,29 +176,43 @@
}
}
-Runtime::ParsedOptions::ParsedOptions(const Options& options, bool ignore_unrecognized) {
+Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) {
+ scoped_ptr<ParsedOptions> parsed(new ParsedOptions());
const char* boot_class_path = getenv("BOOTCLASSPATH");
- boot_image_ = NULL;
- heap_initial_size_ = Heap::kInitialSize;
- heap_maximum_size_ = Heap::kMaximumSize;
+ parsed->boot_image_ = NULL;
+ parsed->heap_initial_size_ = Heap::kInitialSize;
+ parsed->heap_maximum_size_ = Heap::kMaximumSize;
+ parsed->hook_vfprintf_ = vfprintf;
+ parsed->hook_exit_ = exit;
+ parsed->hook_abort_ = abort;
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);
+ parsed->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();
+ parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
} else if (option.starts_with("-Xms")) {
- heap_initial_size_ = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
+ parsed->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);
+ parsed->heap_maximum_size_ = ParseMemoryOption(option.substr(strlen("-Xmx")).data(), 1024);
+ } else if (option.starts_with("-D")) {
+ parsed->properties_.push_back(option.substr(strlen("-D")).data());
+ } else if (option.starts_with("-verbose:")) {
+ Split(option.substr(strlen("-verbose:")).data(), ",", parsed->verbose_);
+ } else if (option == "vfprintf") {
+ parsed->hook_vfprintf_ = reinterpret_cast<int (*)(FILE *, const char*, va_list)>(options[i].second);
+ } else if (option == "exit") {
+ parsed->hook_exit_ = reinterpret_cast<void(*)(jint)>(options[i].second);
+ } else if (option == "abort") {
+ parsed->hook_abort_ = reinterpret_cast<void(*)()>(options[i].second);
} else {
if (!ignore_unrecognized) {
- // TODO: indicate error for JNI_CreateJavaVM and print usage via vfprintf
+ // TODO: print usage via vfprintf
LOG(FATAL) << "Unrecognized option " << option;
+ return NULL;
}
}
}
@@ -198,9 +220,10 @@
if (boot_class_path == NULL) {
boot_class_path = "";
}
- if (boot_class_path_.size() == 0) {
- CreateBootClassPath(boot_class_path, boot_class_path_);
+ if (parsed->boot_class_path_.size() == 0) {
+ CreateBootClassPath(boot_class_path, parsed->boot_class_path_);
}
+ return parsed.release();
}
Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) {
@@ -224,15 +247,27 @@
}
bool Runtime::Init(const Options& options, bool ignore_unrecognized) {
- ParsedOptions parsed_options(options, ignore_unrecognized);
CHECK_EQ(kPageSize, sysconf(_SC_PAGE_SIZE));
+
+ scoped_ptr<ParsedOptions> parsed_options(ParsedOptions::Create(options, ignore_unrecognized));
+ if (parsed_options == NULL) {
+ return false;
+ }
+ vfprintf_ = parsed_options->hook_vfprintf_;
+ exit_ = parsed_options->hook_exit_;
+ abort_ = parsed_options->hook_abort_;
+
thread_list_ = ThreadList::Create();
- Heap::Init(parsed_options.heap_initial_size_,
- parsed_options.heap_maximum_size_);
+
+ 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(parsed_options.boot_class_path_);
+
+ class_linker_ = ClassLinker::Create(parsed_options->boot_class_path_);
+
java_vm_.reset(CreateJavaVM(this));
return true;
}
diff --git a/src/runtime.h b/src/runtime.h
index 9ef7deb..da46ee6 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -3,8 +3,9 @@
#ifndef ART_SRC_RUNTIME_H_
#define ART_SRC_RUNTIME_H_
-#include <vector>
+#include <string>
#include <utility>
+#include <vector>
#include "jni.h"
#include "globals.h"
@@ -17,6 +18,7 @@
class ClassLinker;
class DexFile;
class Heap;
+class String;
class ThreadList;
class Runtime {
@@ -26,12 +28,21 @@
class ParsedOptions {
public:
- ParsedOptions(const Options& options, bool ignore_unrecognized);
+ // returns null if problem parsing and ignore_unrecognized is false
+ static ParsedOptions* Create(const Options& options, bool ignore_unrecognized);
std::vector<DexFile*> boot_class_path_;
const char* boot_image_;
size_t heap_initial_size_;
size_t heap_maximum_size_;
+ jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
+ void (*hook_exit_)(jint status);
+ void (*hook_abort_)();
+ std::vector<std::string> verbose_;
+ std::vector<std::string> properties_;
+
+ private:
+ ParsedOptions() {};
};
// Creates and initializes a new runtime.
@@ -69,12 +80,6 @@
return java_vm_.get();
}
- void SetVfprintfHook(void* hook);
-
- void SetExitHook(void* hook);
-
- void SetAbortHook(void* hook);
-
private:
static void PlatformAbort(const char*, int);
@@ -89,6 +94,11 @@
scoped_ptr<JavaVM> java_vm_;
+ // Hooks supported by JNI_CreateJavaVM
+ jint (*vfprintf_)(FILE* stream, const char* format, va_list ap);
+ void (*exit_)(jint status);
+ void (*abort_)();
+
// A pointer to the active runtime or NULL.
static Runtime* instance_;
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index 3949ac8..3aa257d 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -5,7 +5,7 @@
#include "gtest/gtest.h"
namespace art {
-void ParseClassPath(const char* class_path, std::vector<std::string>* vec);
+void ParseClassPath(const char* class_path, std::vector<std::string>& vec);
}
namespace {
@@ -13,55 +13,55 @@
TEST(RuntimeTest, ParseClassPath) {
std::vector<std::string> vec;
- art::ParseClassPath("", &vec);
+ art::ParseClassPath("", vec);
EXPECT_EQ(0U, vec.size());
vec.clear();
- art::ParseClassPath(":", &vec);
+ art::ParseClassPath(":", vec);
EXPECT_EQ(0U, vec.size());
vec.clear();
- art::ParseClassPath(":foo", &vec);
+ art::ParseClassPath(":foo", vec);
EXPECT_EQ(1U, vec.size());
vec.clear();
- art::ParseClassPath("foo:", &vec);
+ art::ParseClassPath("foo:", vec);
EXPECT_EQ(1U, vec.size());
vec.clear();
- art::ParseClassPath(":foo:", &vec);
+ art::ParseClassPath(":foo:", vec);
EXPECT_EQ(1U, vec.size());
vec.clear();
- art::ParseClassPath("foo:bar", &vec);
+ art::ParseClassPath("foo:bar", vec);
EXPECT_EQ(2U, vec.size());
vec.clear();
- art::ParseClassPath(":foo:bar", &vec);
+ art::ParseClassPath(":foo:bar", vec);
EXPECT_EQ(2U, vec.size());
vec.clear();
- art::ParseClassPath("foo:bar:", &vec);
+ art::ParseClassPath("foo:bar:", vec);
EXPECT_EQ(2U, vec.size());
vec.clear();
- art::ParseClassPath(":foo:bar:", &vec);
+ art::ParseClassPath(":foo:bar:", vec);
EXPECT_EQ(2U, vec.size());
vec.clear();
- art::ParseClassPath("foo:bar:baz", &vec);
+ art::ParseClassPath("foo:bar:baz", vec);
EXPECT_EQ(3U, vec.size());
vec.clear();
- art::ParseClassPath(":foo:bar:baz", &vec);
+ art::ParseClassPath(":foo:bar:baz", vec);
EXPECT_EQ(3U, vec.size());
vec.clear();
- art::ParseClassPath("foo:bar:baz:", &vec);
+ art::ParseClassPath("foo:bar:baz:", vec);
EXPECT_EQ(3U, vec.size());
vec.clear();
- art::ParseClassPath(":foo:bar:baz:", &vec);
+ art::ParseClassPath(":foo:bar:baz:", vec);
EXPECT_EQ(3U, vec.size());
vec.clear();
}