blob: 304c7d2678dc8d0b2f7bb35678f64daafc557986 [file] [log] [blame]
Brian Carlstrom69b15fb2011-09-03 12:25:21 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include <stdio.h>
4#include <stdlib.h>
5
6#include <string>
7#include <vector>
8
9#include "class_linker.h"
10#include "class_loader.h"
11#include "compiler.h"
12#include "image_writer.h"
13#include "runtime.h"
14#include "stringpiece.h"
15
16namespace art {
17
18static void usage() {
19 fprintf(stderr,
20 "Usage: dex2oat [options]...\n"
21 "\n");
22 fprintf(stderr,
23 " --dex-file=<dex-file>: specifies a .dex files to compile. At least one .dex\n"
24 " but more than one may be included. \n"
25 " Example: --dex-file=/system/framework/core.jar\n"
26 "\n");
27 fprintf(stderr,
28 " --image=<file>: specifies the required output image filename.\n"
29 " Example: --image=/system/framework/boot.oat\n"
30 "\n");
31 fprintf(stderr,
32 " --base=<hex-address>: specifies the base address when creating a boot image.\n"
33 " Example: --base=0x50000000\n"
34 "\n");
35 fprintf(stderr,
36 " --boot=<oat-file>: provide the oat file for the boot class path.\n"
37 " Example: --boot=/system/framework/boot.oat\n"
38 "\n");
39 // TODO: remove this by making boot image contain boot DexFile information?
40 fprintf(stderr,
41 " --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
42 " image specified with --boot. \n"
43 " Example: --boot-dex-file=/system/framework/core.jar\n"
44 "\n");
45 fprintf(stderr,
46 " --method may be used to limit compilation to a subset of methods.\n"
47 " Example: --method=Ljava/lang/Object;<init>()V\n"
48 "\n");
Brian Carlstrom16192862011-09-12 17:50:06 -070049 fprintf(stderr,
50 " --strip-prefix may be used to strip a path prefix from dex file names in the\n"
51 " the generated image to match the target file system layout.\n"
52 " Example: --strip-prefix=out/target/product/crespo\n"
53 "\n");
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070054 exit(EXIT_FAILURE);
55}
56
57static void OpenDexFiles(std::vector<const char*>& dex_filenames,
Brian Carlstrom16192862011-09-12 17:50:06 -070058 std::vector<const DexFile*>& dex_files,
59 const std::string& strip_location_prefix) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070060 for (size_t i = 0; i < dex_filenames.size(); i++) {
61 const char* dex_filename = dex_filenames[i];
Brian Carlstrom16192862011-09-12 17:50:06 -070062 const DexFile* dex_file = DexFile::Open(dex_filename, strip_location_prefix);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070063 if (dex_file == NULL) {
64 fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
65 exit(EXIT_FAILURE);
66 }
67 dex_files.push_back(dex_file);
68 }
69}
70
71int dex2oat(int argc, char** argv) {
72 // Skip over argv[0].
73 argv++;
74 argc--;
75
76 if (argc == 0) {
77 fprintf(stderr, "no arguments specified\n");
78 usage();
79 }
80
81 std::vector<const char*> dex_filenames;
82 std::vector<const char*> method_names;
83 const char* image_filename = NULL;
84 std::string boot_image_option;
85 std::vector<const char*> boot_dex_filenames;
86 uintptr_t image_base = 0;
Brian Carlstrom16192862011-09-12 17:50:06 -070087 std::string strip_location_prefix;
88
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070089 for (int i = 0; i < argc; i++) {
90 const StringPiece option(argv[i]);
91 if (option.starts_with("--dex-file=")) {
92 dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
93 } else if (option.starts_with("--method=")) {
94 method_names.push_back(option.substr(strlen("--method=")).data());
95 } else if (option.starts_with("--image=")) {
96 image_filename = option.substr(strlen("--image=")).data();
97 } else if (option.starts_with("--base=")) {
98 const char* image_base_str = option.substr(strlen("--base=")).data();
99 char* end;
100 image_base = strtoul(image_base_str, &end, 16);
101 if (end == image_base_str || *end != '\0') {
102 fprintf(stderr, "could not parse hexadecimal value for option %s\n", option.data());
103 usage();
104 }
105 } else if (option.starts_with("--boot=")) {
106 const char* boot_image_filename = option.substr(strlen("--boot=")).data();
107 boot_image_option.clear();
108 boot_image_option += "-Xbootimage:";
109 boot_image_option += boot_image_filename;
110 } else if (option.starts_with("--boot-dex-file=")) {
111 boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
Brian Carlstrom16192862011-09-12 17:50:06 -0700112 } else if (option.starts_with("--strip-prefix=")) {
113 strip_location_prefix = option.substr(strlen("--strip-prefix=")).data();
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700114 } else {
115 fprintf(stderr, "unknown argument %s\n", option.data());
116 usage();
117 }
118 }
119
120 if (image_filename == NULL) {
121 fprintf(stderr, "--image file name not specified\n");
122 return EXIT_FAILURE;
123 }
124
125 if (boot_image_option.empty()) {
126 if (image_base == 0) {
127 fprintf(stderr, "non-zero --base not specified\n");
128 return EXIT_FAILURE;
129 }
130 } else {
131 if (boot_dex_filenames.empty()) {
132 fprintf(stderr, "no --boot-dex-file specified with --boot\n");
133 return EXIT_FAILURE;
134 }
135 }
136
137 std::vector<const DexFile*> dex_files;
Brian Carlstrom16192862011-09-12 17:50:06 -0700138 OpenDexFiles(dex_filenames, dex_files, strip_location_prefix);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700139
140 std::vector<const DexFile*> boot_dex_files;
Brian Carlstrom16192862011-09-12 17:50:06 -0700141 OpenDexFiles(boot_dex_filenames, boot_dex_files, strip_location_prefix);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700142
143 Runtime::Options options;
144 if (boot_image_option.empty()) {
145 options.push_back(std::make_pair("bootclasspath", &dex_files));
146 } else {
147 options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
148 options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
149 }
150 UniquePtr<Runtime> runtime(Runtime::Create(options, false));
151 if (runtime.get() == NULL) {
152 fprintf(stderr, "could not create runtime\n");
153 return EXIT_FAILURE;
154 }
155 ClassLinker* class_linker = runtime->GetClassLinker();
156
157 // If we have an existing boot image, position new space after it
158 if (!boot_image_option.empty()) {
159 Space* boot_space = Heap::GetBootSpace();
160 CHECK(boot_space != NULL);
161 image_base = RoundUp(reinterpret_cast<uintptr_t>(boot_space->GetLimit()), kPageSize);
162 }
163
164 // ClassLoader creation needs to come after Runtime::Create
165 const ClassLoader* class_loader;
166 if (boot_image_option.empty()) {
167 class_loader = NULL;
168 } else {
169 for (size_t i = 0; i < dex_files.size(); i++) {
170 class_linker->RegisterDexFile(*dex_files[i]);
171 }
172 class_loader = PathClassLoader::Alloc(dex_files);
173 }
174
Brian Carlstrom16192862011-09-12 17:50:06 -0700175 // if we loaded an existing image, we will reuse its stub array.
176 if (!runtime->HasJniStubArray()) {
177 runtime->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
178 }
179
Ian Rogers2c8f6532011-09-02 17:16:34 -0700180 Compiler compiler(kThumb2);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700181 if (method_names.empty()) {
182 compiler.CompileAll(class_loader);
183 } else {
184 for (size_t i = 0; i < method_names.size(); i++) {
185 // names are actually class_descriptor + name + signature.
186 // example: Ljava/lang/Object;<init>()V
187 StringPiece method_name = method_names[i];
188 size_t end_of_class_descriptor = method_name.find(';');
189 if (end_of_class_descriptor == method_name.npos) {
190 fprintf(stderr, "could not find class descriptor in method %s\n", method_name.data());
191 return EXIT_FAILURE;
192 }
193 end_of_class_descriptor++; // want to include ;
194 std::string class_descriptor = method_name.substr(0, end_of_class_descriptor).ToString();
195 size_t end_of_name = method_name.find('(', end_of_class_descriptor);
196 if (end_of_name == method_name.npos) {
197 fprintf(stderr, "could not find start of method signature in method %s\n", method_name.data());
198 return EXIT_FAILURE;
199 }
200 std::string name = method_name.substr(end_of_class_descriptor,
201 end_of_name - end_of_class_descriptor).ToString();
202 std::string signature = method_name.substr(end_of_name).ToString();
203
204 Class* klass = class_linker->FindClass(class_descriptor, class_loader);
205 if (klass == NULL) {
206 fprintf(stderr, "could not find class for descriptor %s in method %s\n",
207 class_descriptor.c_str(), method_name.data());
208 return EXIT_FAILURE;
209 }
210 Method* method = klass->FindDirectMethod(name, signature);
211 if (method == NULL) {
212 method = klass->FindVirtualMethod(name, signature);
213 }
214 if (method == NULL) {
215 fprintf(stderr, "could not find method %s with signature %s in class %s for method argument %s\n",
216 name.c_str(),
217 signature.c_str(),
218 class_descriptor.c_str(),
219 method_name.data());
220 return EXIT_FAILURE;
221 }
222 compiler.CompileOne(method);
223 }
224 }
225
226 ImageWriter writer;
227 if (!writer.Write(image_filename, image_base)) {
228 fprintf(stderr, "could not write image %s\n", image_filename);
229 return EXIT_FAILURE;
230 }
231
232 return EXIT_SUCCESS;
233}
234
235} // namespace art
236
237int main(int argc, char** argv) {
238 return art::dex2oat(argc, argv);
239}