blob: 864ca763c3e19ddac53637bba1ecd10b10ca528c [file] [log] [blame]
Andreas Gampee1459ae2016-06-29 09:36:30 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Gampe7adeda82016-07-25 08:27:35 -070017#include <regex>
18#include <sstream>
Andreas Gampee1459ae2016-06-29 09:36:30 -070019#include <string>
20#include <vector>
Andreas Gampee1459ae2016-06-29 09:36:30 -070021
Andreas Gampe46ee31b2016-12-14 10:11:49 -080022#include <sys/wait.h>
23#include <unistd.h>
24
25#include "android-base/stringprintf.h"
26
Andreas Gampee1459ae2016-06-29 09:36:30 -070027#include "common_runtime_test.h"
28
29#include "base/logging.h"
30#include "base/macros.h"
Jeff Hao608f2ce2016-10-19 11:17:11 -070031#include "dex_file-inl.h"
Andreas Gampee1459ae2016-06-29 09:36:30 -070032#include "dex2oat_environment_test.h"
Calin Juravle33083d62017-01-18 15:29:12 -080033#include "jit/profile_compilation_info.h"
Andreas Gampe67f02822016-06-24 21:05:23 -070034#include "oat.h"
35#include "oat_file.h"
Andreas Gampee1459ae2016-06-29 09:36:30 -070036#include "utils.h"
37
Andreas Gampee1459ae2016-06-29 09:36:30 -070038namespace art {
39
40class Dex2oatTest : public Dex2oatEnvironmentTest {
41 public:
42 virtual void TearDown() OVERRIDE {
43 Dex2oatEnvironmentTest::TearDown();
44
45 output_ = "";
46 error_msg_ = "";
47 success_ = false;
48 }
49
50 protected:
51 void GenerateOdexForTest(const std::string& dex_location,
52 const std::string& odex_location,
53 CompilerFilter::Filter filter,
54 const std::vector<std::string>& extra_args = {},
55 bool expect_success = true) {
56 std::vector<std::string> args;
57 args.push_back("--dex-file=" + dex_location);
58 args.push_back("--oat-file=" + odex_location);
59 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
60 args.push_back("--runtime-arg");
61 args.push_back("-Xnorelocate");
62
63 args.insert(args.end(), extra_args.begin(), extra_args.end());
64
65 std::string error_msg;
66 bool success = Dex2Oat(args, &error_msg);
67
68 if (expect_success) {
69 ASSERT_TRUE(success) << error_msg;
70
71 // Verify the odex file was generated as expected.
72 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
73 odex_location.c_str(),
74 nullptr,
75 nullptr,
76 false,
77 /*low_4gb*/false,
78 dex_location.c_str(),
79 &error_msg));
80 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
81
82 CheckFilter(filter, odex_file->GetCompilerFilter());
83 } else {
84 ASSERT_FALSE(success) << output_;
85
86 error_msg_ = error_msg;
87
88 // Verify there's no loadable odex file.
89 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
90 odex_location.c_str(),
91 nullptr,
92 nullptr,
93 false,
94 /*low_4gb*/false,
95 dex_location.c_str(),
96 &error_msg));
97 ASSERT_TRUE(odex_file.get() == nullptr);
98 }
99 }
100
101 // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
102 // in subclasses when equality is not expected.
103 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
104 EXPECT_EQ(expected, actual);
105 }
106
107 bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
108 Runtime* runtime = Runtime::Current();
109
110 const std::vector<gc::space::ImageSpace*>& image_spaces =
111 runtime->GetHeap()->GetBootImageSpaces();
112 if (image_spaces.empty()) {
113 *error_msg = "No image location found for Dex2Oat.";
114 return false;
115 }
116 std::string image_location = image_spaces[0]->GetImageLocation();
117
118 std::vector<std::string> argv;
119 argv.push_back(runtime->GetCompilerExecutable());
120 argv.push_back("--runtime-arg");
121 argv.push_back("-classpath");
122 argv.push_back("--runtime-arg");
123 std::string class_path = runtime->GetClassPathString();
124 if (class_path == "") {
125 class_path = OatFile::kSpecialSharedLibrary;
126 }
127 argv.push_back(class_path);
Nicolas Geoffray433b79a2017-01-30 20:54:45 +0000128 if (runtime->IsJavaDebuggable()) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700129 argv.push_back("--debuggable");
130 }
131 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
132
133 if (!runtime->IsVerificationEnabled()) {
134 argv.push_back("--compiler-filter=verify-none");
135 }
136
137 if (runtime->MustRelocateIfPossible()) {
138 argv.push_back("--runtime-arg");
139 argv.push_back("-Xrelocate");
140 } else {
141 argv.push_back("--runtime-arg");
142 argv.push_back("-Xnorelocate");
143 }
144
145 if (!kIsTargetBuild) {
146 argv.push_back("--host");
147 }
148
149 argv.push_back("--boot-image=" + image_location);
150
151 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
152 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
153
154 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
155
156 // We must set --android-root.
157 const char* android_root = getenv("ANDROID_ROOT");
158 CHECK(android_root != nullptr);
159 argv.push_back("--android-root=" + std::string(android_root));
160
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100161 int link[2];
Andreas Gampee1459ae2016-06-29 09:36:30 -0700162
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100163 if (pipe(link) == -1) {
164 return false;
165 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700166
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100167 pid_t pid = fork();
168 if (pid == -1) {
169 return false;
170 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700171
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100172 if (pid == 0) {
173 // We need dex2oat to actually log things.
174 setenv("ANDROID_LOG_TAGS", "*:d", 1);
175 dup2(link[1], STDERR_FILENO);
176 close(link[0]);
177 close(link[1]);
178 std::vector<const char*> c_args;
179 for (const std::string& str : argv) {
180 c_args.push_back(str.c_str());
Andreas Gampee1459ae2016-06-29 09:36:30 -0700181 }
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100182 c_args.push_back(nullptr);
183 execv(c_args[0], const_cast<char* const*>(c_args.data()));
184 exit(1);
185 } else {
186 close(link[1]);
187 char buffer[128];
188 memset(buffer, 0, 128);
189 ssize_t bytes_read = 0;
Andreas Gampee1459ae2016-06-29 09:36:30 -0700190
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100191 while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
192 output_ += std::string(buffer, bytes_read);
193 }
194 close(link[0]);
195 int status = 0;
196 if (waitpid(pid, &status, 0) != -1) {
197 success_ = (status == 0);
198 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700199 }
200 return success_;
201 }
202
203 std::string output_ = "";
204 std::string error_msg_ = "";
205 bool success_ = false;
206};
207
208class Dex2oatSwapTest : public Dex2oatTest {
209 protected:
210 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
211 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
212 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
213
Andreas Gampe7adeda82016-07-25 08:27:35 -0700214 Copy(GetTestDexFileName(), dex_location);
Andreas Gampee1459ae2016-06-29 09:36:30 -0700215
216 std::vector<std::string> copy(extra_args);
217
218 std::unique_ptr<ScratchFile> sf;
219 if (use_fd) {
220 sf.reset(new ScratchFile());
Andreas Gampe46ee31b2016-12-14 10:11:49 -0800221 copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
Andreas Gampee1459ae2016-06-29 09:36:30 -0700222 } else {
223 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
224 copy.push_back("--swap-file=" + swap_location);
225 }
226 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
227
228 CheckValidity();
229 ASSERT_TRUE(success_);
230 CheckResult(expect_use);
231 }
232
Andreas Gampe7adeda82016-07-25 08:27:35 -0700233 virtual std::string GetTestDexFileName() {
234 return GetDexSrc1();
235 }
236
237 virtual void CheckResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700238 if (kIsTargetBuild) {
239 CheckTargetResult(expect_use);
240 } else {
241 CheckHostResult(expect_use);
242 }
243 }
244
Andreas Gampe7adeda82016-07-25 08:27:35 -0700245 virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700246 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
247 // something for variants with file descriptor where we can control the lifetime of
248 // the swap file and thus take a look at it.
249 }
250
Andreas Gampe7adeda82016-07-25 08:27:35 -0700251 virtual void CheckHostResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700252 if (!kIsTargetBuild) {
253 if (expect_use) {
254 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
255 << output_;
256 } else {
257 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
258 << output_;
259 }
260 }
261 }
262
263 // Check whether the dex2oat run was really successful.
Andreas Gampe7adeda82016-07-25 08:27:35 -0700264 virtual void CheckValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700265 if (kIsTargetBuild) {
266 CheckTargetValidity();
267 } else {
268 CheckHostValidity();
269 }
270 }
271
Andreas Gampe7adeda82016-07-25 08:27:35 -0700272 virtual void CheckTargetValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700273 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
274 // something for variants with file descriptor where we can control the lifetime of
275 // the swap file and thus take a look at it.
276 }
277
278 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
Andreas Gampe7adeda82016-07-25 08:27:35 -0700279 virtual void CheckHostValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700280 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
281 }
282};
283
284TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
285 RunTest(false /* use_fd */, false /* expect_use */);
286 RunTest(true /* use_fd */, false /* expect_use */);
287}
288
289TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
290 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
291 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
292}
293
294TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
295 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
296 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
297}
298
299TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
300 RunTest(false /* use_fd */,
301 true /* expect_use */,
302 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
303 RunTest(true /* use_fd */,
304 true /* expect_use */,
305 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
306}
307
Andreas Gampe7adeda82016-07-25 08:27:35 -0700308class Dex2oatSwapUseTest : public Dex2oatSwapTest {
309 protected:
310 void CheckHostResult(bool expect_use) OVERRIDE {
311 if (!kIsTargetBuild) {
312 if (expect_use) {
313 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
314 << output_;
315 } else {
316 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
317 << output_;
318 }
319 }
320 }
321
322 std::string GetTestDexFileName() OVERRIDE {
323 // Use Statics as it has a handful of functions.
324 return CommonRuntimeTest::GetTestDexFileName("Statics");
325 }
326
327 void GrabResult1() {
328 if (!kIsTargetBuild) {
329 native_alloc_1_ = ParseNativeAlloc();
330 swap_1_ = ParseSwap(false /* expected */);
331 } else {
332 native_alloc_1_ = std::numeric_limits<size_t>::max();
333 swap_1_ = 0;
334 }
335 }
336
337 void GrabResult2() {
338 if (!kIsTargetBuild) {
339 native_alloc_2_ = ParseNativeAlloc();
340 swap_2_ = ParseSwap(true /* expected */);
341 } else {
342 native_alloc_2_ = 0;
343 swap_2_ = std::numeric_limits<size_t>::max();
344 }
345 }
346
347 private:
348 size_t ParseNativeAlloc() {
349 std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
350 std::smatch native_alloc_match;
351 bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
352 if (!found) {
353 EXPECT_TRUE(found);
354 return 0;
355 }
356 if (native_alloc_match.size() != 2U) {
357 EXPECT_EQ(native_alloc_match.size(), 2U);
358 return 0;
359 }
360
361 std::istringstream stream(native_alloc_match[1].str());
362 size_t value;
363 stream >> value;
364
365 return value;
366 }
367
368 size_t ParseSwap(bool expected) {
369 std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
370 std::smatch swap_match;
371 bool found = std::regex_search(output_, swap_match, swap_regex);
372 if (found != expected) {
373 EXPECT_EQ(expected, found);
374 return 0;
375 }
376
377 if (!found) {
378 return 0;
379 }
380
381 if (swap_match.size() != 2U) {
382 EXPECT_EQ(swap_match.size(), 2U);
383 return 0;
384 }
385
386 std::istringstream stream(swap_match[1].str());
387 size_t value;
388 stream >> value;
389
390 return value;
391 }
392
393 protected:
394 size_t native_alloc_1_;
395 size_t native_alloc_2_;
396
397 size_t swap_1_;
398 size_t swap_2_;
399};
400
401TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
Roland Levillain63b6eb42016-07-28 16:37:28 +0100402 // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
403 // hold true on some x86 systems when read barriers are enabled;
404 // disable this test while we investigate (b/29259363).
405 TEST_DISABLED_FOR_READ_BARRIER_ON_X86();
406
Andreas Gampe7adeda82016-07-25 08:27:35 -0700407 RunTest(false /* use_fd */,
408 false /* expect_use */);
409 GrabResult1();
410 std::string output_1 = output_;
411
412 output_ = "";
413
414 RunTest(false /* use_fd */,
415 true /* expect_use */,
416 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
417 GrabResult2();
418 std::string output_2 = output_;
419
420 if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
421 EXPECT_LT(native_alloc_2_, native_alloc_1_);
422 EXPECT_LT(swap_1_, swap_2_);
423
424 LOG(ERROR) << output_1;
425 LOG(ERROR) << output_2;
426 }
427}
428
Andreas Gampe67f02822016-06-24 21:05:23 -0700429class Dex2oatVeryLargeTest : public Dex2oatTest {
430 protected:
431 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
432 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
433 // Ignore, we'll do our own checks.
434 }
435
436 void RunTest(CompilerFilter::Filter filter,
437 bool expect_large,
438 const std::vector<std::string>& extra_args = {}) {
439 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
440 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
441
442 Copy(GetDexSrc1(), dex_location);
443
Andreas Gampeca620d72016-11-08 08:09:33 -0800444 GenerateOdexForTest(dex_location, odex_location, filter, extra_args);
Andreas Gampe67f02822016-06-24 21:05:23 -0700445
446 CheckValidity();
447 ASSERT_TRUE(success_);
448 CheckResult(dex_location, odex_location, filter, expect_large);
449 }
450
451 void CheckResult(const std::string& dex_location,
452 const std::string& odex_location,
453 CompilerFilter::Filter filter,
454 bool expect_large) {
455 // Host/target independent checks.
456 std::string error_msg;
457 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
458 odex_location.c_str(),
459 nullptr,
460 nullptr,
461 false,
462 /*low_4gb*/false,
463 dex_location.c_str(),
464 &error_msg));
465 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
466 if (expect_large) {
467 // Note: we cannot check the following:
468 // EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
469 // odex_file->GetCompilerFilter()));
470 // The reason is that the filter override currently happens when the dex files are
471 // loaded in dex2oat, which is after the oat file has been started. Thus, the header
472 // store cannot be changed, and the original filter is set in stone.
473
474 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
475 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
476 ASSERT_TRUE(dex_file != nullptr);
477 uint32_t class_def_count = dex_file->NumClassDefs();
478 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
479 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
480 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
481 EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
482 }
483 }
484
485 // If the input filter was "below," it should have been used.
486 if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
487 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
488 }
489 } else {
490 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
491 }
492
493 // Host/target dependent checks.
494 if (kIsTargetBuild) {
495 CheckTargetResult(expect_large);
496 } else {
497 CheckHostResult(expect_large);
498 }
499 }
500
501 void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
502 // TODO: Ignore for now. May do something for fd things.
503 }
504
505 void CheckHostResult(bool expect_large) {
506 if (!kIsTargetBuild) {
507 if (expect_large) {
508 EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
509 std::string::npos)
510 << output_;
511 } else {
512 EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
513 std::string::npos)
514 << output_;
515 }
516 }
517 }
518
519 // Check whether the dex2oat run was really successful.
520 void CheckValidity() {
521 if (kIsTargetBuild) {
522 CheckTargetValidity();
523 } else {
524 CheckHostValidity();
525 }
526 }
527
528 void CheckTargetValidity() {
529 // TODO: Ignore for now.
530 }
531
532 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
533 void CheckHostValidity() {
534 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
535 }
536};
537
538TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
539 RunTest(CompilerFilter::kVerifyNone, false);
540 RunTest(CompilerFilter::kVerifyAtRuntime, false);
541 RunTest(CompilerFilter::kInterpretOnly, false);
542 RunTest(CompilerFilter::kSpeed, false);
543
544 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
545 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
546 RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
547 RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
548}
549
550TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
551 RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
552 RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
553 RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
554 RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
555}
556
Jeff Hao608f2ce2016-10-19 11:17:11 -0700557class Dex2oatLayoutTest : public Dex2oatTest {
558 protected:
559 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
560 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
561 // Ignore, we'll do our own checks.
562 }
563
Jeff Hao41fba6a2016-11-28 11:53:33 -0800564 // Emits a profile with a single dex file with the given location and a single class index of 1.
565 void GenerateProfile(const std::string& test_profile,
566 const std::string& dex_location,
567 uint32_t checksum) {
568 int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
569 CHECK_GE(profile_test_fd, 0);
570
571 ProfileCompilationInfo info;
572 std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
573 info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1));
574 bool result = info.Save(profile_test_fd);
575 close(profile_test_fd);
576 ASSERT_TRUE(result);
577 }
578
Jeff Hao608f2ce2016-10-19 11:17:11 -0700579 void RunTest() {
580 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
581 std::string profile_location = GetScratchDir() + "/primary.prof";
582 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
583
584 Copy(GetDexSrc2(), dex_location);
Jeff Hao41fba6a2016-11-28 11:53:33 -0800585 const char* location = dex_location.c_str();
586 std::string error_msg;
587 std::vector<std::unique_ptr<const DexFile>> dex_files;
588 ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
589 EXPECT_EQ(dex_files.size(), 1U);
590 std::unique_ptr<const DexFile>& dex_file = dex_files[0];
591 GenerateProfile(profile_location, dex_location, dex_file->GetLocationChecksum());
Jeff Hao608f2ce2016-10-19 11:17:11 -0700592
593 const std::vector<std::string>& extra_args = { "--profile-file=" + profile_location };
594 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kLayoutProfile, extra_args);
595
596 CheckValidity();
597 ASSERT_TRUE(success_);
598 CheckResult(dex_location, odex_location);
599 }
600 void CheckResult(const std::string& dex_location, const std::string& odex_location) {
601 // Host/target independent checks.
602 std::string error_msg;
603 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
604 odex_location.c_str(),
605 nullptr,
606 nullptr,
607 false,
608 /*low_4gb*/false,
609 dex_location.c_str(),
610 &error_msg));
611 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
612
Jeff Hao042e8982016-10-19 11:17:11 -0700613 const char* location = dex_location.c_str();
614 std::vector<std::unique_ptr<const DexFile>> dex_files;
615 ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
616 EXPECT_EQ(dex_files.size(), 1U);
617 std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
618
Jeff Hao608f2ce2016-10-19 11:17:11 -0700619 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
Jeff Hao042e8982016-10-19 11:17:11 -0700620 std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
621 ASSERT_TRUE(new_dex_file != nullptr);
622 uint32_t class_def_count = new_dex_file->NumClassDefs();
Jeff Hao608f2ce2016-10-19 11:17:11 -0700623 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
Jeff Hao042e8982016-10-19 11:17:11 -0700624 ASSERT_GE(class_def_count, 2U);
625
626 // The new layout swaps the classes at indexes 0 and 1.
627 std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
628 std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
629 std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
630 std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
631 EXPECT_EQ(old_class0, new_class1);
632 EXPECT_EQ(old_class1, new_class0);
Jeff Hao608f2ce2016-10-19 11:17:11 -0700633 }
634
635 EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kLayoutProfile);
636 }
637
638 // Check whether the dex2oat run was really successful.
639 void CheckValidity() {
640 if (kIsTargetBuild) {
641 CheckTargetValidity();
642 } else {
643 CheckHostValidity();
644 }
645 }
646
647 void CheckTargetValidity() {
648 // TODO: Ignore for now.
649 }
650
651 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
652 void CheckHostValidity() {
653 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
654 }
655 };
656
657TEST_F(Dex2oatLayoutTest, TestLayout) {
658 RunTest();
659}
660
Andreas Gampee1459ae2016-06-29 09:36:30 -0700661} // namespace art