blob: 411ed670e5e1ba3b48a381351b2f584837fa21d3 [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
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070010#include "class_linker.h"
11#include "heap.h"
Carl Shapirofc322c72011-07-27 00:20:01 -070012#include "scoped_ptr.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070013#include "thread.h"
Carl Shapiro61e019d2011-07-14 16:53:09 -070014
Carl Shapiro1fb86202011-06-27 17:43:13 -070015namespace art {
16
Carl Shapiro2ed144c2011-07-26 16:52:08 -070017Runtime* Runtime::instance_ = NULL;
18
Carl Shapiro61e019d2011-07-14 16:53:09 -070019Runtime::~Runtime() {
20 // TODO: use a smart pointer instead.
21 delete class_linker_;
Carl Shapiro69759ea2011-07-21 18:13:35 -070022 Heap::Destroy();
Carl Shapiro61e019d2011-07-14 16:53:09 -070023 delete thread_list_;
Carl Shapiro4acf4642011-07-26 18:54:13 -070024 // TODO: acquire a static mutex on Runtime to avoid racing.
25 CHECK(instance_ == this);
26 instance_ = NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -070027}
28
Elliott Hughesffe67362011-07-17 12:09:27 -070029void Runtime::Abort(const char* file, int line) {
30 // Get any pending output out of the way.
31 fflush(NULL);
32
33 // Many people have difficulty distinguish aborts from crashes,
34 // so be explicit.
35 LogMessage(file, line, ERROR, -1).stream() << "Runtime aborting...";
36
37 // TODO: if we support an abort hook, call it here.
38
39 // Perform any platform-specific pre-abort actions.
40 PlatformAbort(file, line);
41
42 // If we call abort(3) on a device, all threads in the process
Carl Shapiro69759ea2011-07-21 18:13:35 -070043 // receive SIGABRT. debuggerd dumps the stack trace of the main
44 // thread, whether or not that was the thread that failed. By
45 // stuffing a value into a bogus address, we cause a segmentation
Elliott Hughesffe67362011-07-17 12:09:27 -070046 // fault in the current thread, and get a useful log from debuggerd.
47 // We can also trivially tell the difference between a VM crash and
48 // a deliberate abort by looking at the fault address.
49 *reinterpret_cast<char*>(0xdeadd00d) = 38;
50 abort();
51
52 // notreached
53}
54
Carl Shapirod3c15752011-07-27 16:27:22 -070055// Splits a colon delimited list of pathname elements into a vector of
56// strings. Empty strings will be omitted.
Carl Shapirofc322c72011-07-27 00:20:01 -070057void ParseClassPath(const char* class_path, std::vector<std::string>* vec) {
58 CHECK(vec != NULL);
59 scoped_ptr_malloc<char> tmp(strdup(class_path));
60 char* full = tmp.get();
61 char* p = full;
Carl Shapirod3c15752011-07-27 16:27:22 -070062 while (p != NULL) {
Carl Shapirofc322c72011-07-27 00:20:01 -070063 p = strpbrk(full, ":");
64 if (p != NULL) {
65 p[0] = '\0';
66 }
67 if (full[0] != '\0') {
68 vec->push_back(std::string(full));
69 }
Carl Shapirod3c15752011-07-27 16:27:22 -070070 if (p != NULL) {
Carl Shapirofc322c72011-07-27 00:20:01 -070071 full = p + 1;
72 }
73 }
74}
75
Brian Carlstrom8a436592011-08-15 21:27:23 -070076
77
78// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
79// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
80// [gG] gigabytes.
81//
82// "s" should point just past the "-Xm?" part of the string.
83// "min" specifies the lowest acceptable value described by "s".
84// "div" specifies a divisor, e.g. 1024 if the value must be a multiple
85// of 1024.
86//
87// The spec says the -Xmx and -Xms options must be multiples of 1024. It
88// doesn't say anything about -Xss.
89//
90// Returns 0 (a useless size) if "s" is malformed or specifies a low or
91// non-evenly-divisible value.
92//
93size_t ParseMemoryOption(const char *s, size_t div) {
94 // strtoul accepts a leading [+-], which we don't want,
95 // so make sure our string starts with a decimal digit.
96 if (isdigit(*s)) {
97 const char *s2;
98 size_t val = strtoul(s, (char **)&s2, 10);
99 if (s2 != s) {
100 // s2 should be pointing just after the number.
101 // If this is the end of the string, the user
102 // has specified a number of bytes. Otherwise,
103 // there should be exactly one more character
104 // that specifies a multiplier.
105 if (*s2 != '\0') {
106 // The remainder of the string is either a single multiplier
107 // character, or nothing to indicate that the value is in
108 // bytes.
109 char c = *s2++;
110 if (*s2 == '\0') {
111 size_t mul;
112 if (c == '\0') {
113 mul = 1;
114 } else if (c == 'k' || c == 'K') {
115 mul = 1024;
116 } else if (c == 'm' || c == 'M') {
117 mul = 1024 * 1024;
118 } else if (c == 'g' || c == 'G') {
119 mul = 1024 * 1024 * 1024;
120 } else {
121 // Unknown multiplier character.
122 return 0;
123 }
124
125 if (val <= std::numeric_limits<size_t>::max() / mul) {
126 val *= mul;
127 } else {
128 // Clamp to a multiple of 1024.
129 val = std::numeric_limits<size_t>::max() & ~(1024-1);
130 }
131 } else {
132 // There's more than one character after the numeric part.
133 return 0;
134 }
135 }
136 // The man page says that a -Xm value must be a multiple of 1024.
137 if (val % div == 0) {
138 return val;
139 }
Carl Shapirofc322c72011-07-27 00:20:01 -0700140 }
141 }
Brian Carlstrom8a436592011-08-15 21:27:23 -0700142 return 0;
Carl Shapirofc322c72011-07-27 00:20:01 -0700143}
144
Elliott Hughes40ef99e2011-08-11 17:44:34 -0700145DexFile* Open(const std::string& filename) {
146 if (filename.size() < 4) {
147 LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'";
148 return NULL;
149 }
150 std::string suffix(filename.substr(filename.size() - 4));
151 if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") {
152 return DexFile::OpenZip(filename);
153 } else {
154 return DexFile::OpenFile(filename);
155 }
156}
157
Brian Carlstrom8a436592011-08-15 21:27:23 -0700158void CreateBootClassPath(const char* boot_class_path_cstr,
159 std::vector<DexFile*>& boot_class_path_vector) {
160 CHECK(boot_class_path_cstr != NULL);
Carl Shapirofc322c72011-07-27 00:20:01 -0700161 std::vector<std::string> parsed;
Brian Carlstrom8a436592011-08-15 21:27:23 -0700162 ParseClassPath(boot_class_path_cstr, &parsed);
Carl Shapirofc322c72011-07-27 00:20:01 -0700163 for (size_t i = 0; i < parsed.size(); ++i) {
Elliott Hughes40ef99e2011-08-11 17:44:34 -0700164 DexFile* dex_file = Open(parsed[i]);
Carl Shapirofc322c72011-07-27 00:20:01 -0700165 if (dex_file != NULL) {
Brian Carlstrom8a436592011-08-15 21:27:23 -0700166 boot_class_path_vector.push_back(dex_file);
Carl Shapirofc322c72011-07-27 00:20:01 -0700167 }
168 }
169}
170
Brian Carlstrom8a436592011-08-15 21:27:23 -0700171Runtime::ParsedOptions::ParsedOptions(const Options& options, bool ignore_unrecognized) {
172 const char* boot_class_path = getenv("BOOTCLASSPATH");
173 boot_image_ = NULL;
174 heap_initial_size_ = Heap::kInitialSize;
175 heap_maximum_size_ = Heap::kMaximumSize;
176
177 for (size_t i = 0; i < options.size(); ++i) {
178 const StringPiece& option = options[i].first;
179 // TODO parse -D, -verbose, vprintf, exit, abort
180 if (option.starts_with("-Xbootclasspath:")) {
181 boot_class_path = option.substr(strlen("-Xbootclasspath:")).data();
182 } else if (option == "bootclasspath") {
183 boot_class_path_ = *reinterpret_cast<const std::vector<DexFile*>*>(options[i].second);
184 } else if (option.starts_with("-Xbootimage:")) {
185 boot_image_ = option.substr(strlen("-Xbootimage:")).data();
186 } else if (option.starts_with("-Xms")) {
187 heap_initial_size_ = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
188 } else if (option.starts_with("-Xmx")) {
189 heap_maximum_size_ = ParseMemoryOption(option.substr(strlen("-Xmx")).data(), 1024);
190 } else {
191 if (!ignore_unrecognized) {
192 // TODO: indicate error for JNI_CreateJavaVM and print usage via vfprintf
193 LOG(FATAL) << "Unrecognized option " << option;
194 }
195 }
196 }
197
198 if (boot_class_path == NULL) {
199 boot_class_path = "";
200 }
201 if (boot_class_path_.size() == 0) {
202 CreateBootClassPath(boot_class_path, boot_class_path_);
203 }
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700204}
205
Brian Carlstrom8a436592011-08-15 21:27:23 -0700206Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) {
207 Runtime::Options options;
208 options.push_back(std::make_pair("bootclasspath", &boot_class_path));
209 return Runtime::Create(options, false);
210}
211
212Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700213 // TODO: acquire a static mutex on Runtime to avoid racing.
214 if (Runtime::instance_ != NULL) {
215 return NULL;
216 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700217 scoped_ptr<Runtime> runtime(new Runtime());
Brian Carlstrom8a436592011-08-15 21:27:23 -0700218 bool success = runtime->Init(options, ignore_unrecognized);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700219 if (!success) {
220 return NULL;
221 } else {
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700222 return Runtime::instance_ = runtime.release();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700223 }
224}
225
Brian Carlstrom8a436592011-08-15 21:27:23 -0700226bool Runtime::Init(const Options& options, bool ignore_unrecognized) {
227 ParsedOptions parsed_options(options, ignore_unrecognized);
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700228 CHECK_EQ(kPageSize, sysconf(_SC_PAGE_SIZE));
Carl Shapiro61e019d2011-07-14 16:53:09 -0700229 thread_list_ = ThreadList::Create();
Brian Carlstrom8a436592011-08-15 21:27:23 -0700230 Heap::Init(parsed_options.heap_initial_size_,
231 parsed_options.heap_maximum_size_);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700232 Thread::Init();
233 Thread* current_thread = Thread::Attach();
234 thread_list_->Register(current_thread);
Brian Carlstrom8a436592011-08-15 21:27:23 -0700235 class_linker_ = ClassLinker::Create(parsed_options.boot_class_path_);
Elliott Hughesf2682d52011-08-15 16:37:04 -0700236 java_vm_.reset(CreateJavaVM(this));
Carl Shapiro1fb86202011-06-27 17:43:13 -0700237 return true;
238}
239
Elliott Hughes40ef99e2011-08-11 17:44:34 -0700240bool Runtime::AttachCurrentThread(const char* name, JNIEnv** penv) {
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700241 return Thread::Attach() != NULL;
242}
243
Elliott Hughes40ef99e2011-08-11 17:44:34 -0700244bool Runtime::AttachCurrentThreadAsDaemon(const char* name, JNIEnv** penv) {
Carl Shapiro2ed144c2011-07-26 16:52:08 -0700245 // TODO: do something different for daemon threads.
Ian Rogersb033c752011-07-20 12:22:35 -0700246 return Thread::Attach() != NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700247}
248
Ian Rogersb033c752011-07-20 12:22:35 -0700249bool Runtime::DetachCurrentThread() {
Elliott Hughes53b61312011-08-12 18:28:20 -0700250 UNIMPLEMENTED(WARNING);
Ian Rogersb033c752011-07-20 12:22:35 -0700251 return true;
Carl Shapiro1fb86202011-06-27 17:43:13 -0700252}
253
254} // namespace art