blob: c91240e19d5f084f5f5d8ec07c087a03ed9d4f53 [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
Igor Murashkin5573c372017-11-16 13:34:30 -080017#include <regex>
Andreas Gampe7adeda82016-07-25 08:27:35 -070018#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
Andreas Gampe57943812017-12-06 21:39:13 -080025#include <android-base/logging.h>
26#include <android-base/stringprintf.h>
Andreas Gampe46ee31b2016-12-14 10:11:49 -080027
Andreas Gampee1459ae2016-06-29 09:36:30 -070028#include "common_runtime_test.h"
29
Andreas Gampee1459ae2016-06-29 09:36:30 -070030#include "base/macros.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070031#include "base/mutex-inl.h"
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +010032#include "bytecode_utils.h"
David Sehr9e734c72018-01-04 17:56:19 -080033#include "dex/code_item_accessors-inl.h"
34#include "dex/dex_file-inl.h"
35#include "dex/dex_file_loader.h"
Andreas Gampee1459ae2016-06-29 09:36:30 -070036#include "dex2oat_environment_test.h"
Andreas Gampef7882972017-03-20 16:35:24 -070037#include "dex2oat_return_codes.h"
Calin Juravle33083d62017-01-18 15:29:12 -080038#include "jit/profile_compilation_info.h"
Andreas Gampe67f02822016-06-24 21:05:23 -070039#include "oat.h"
40#include "oat_file.h"
Andreas Gampee1459ae2016-06-29 09:36:30 -070041#include "utils.h"
42
Andreas Gampee1459ae2016-06-29 09:36:30 -070043namespace art {
44
Mathieu Chartierea650f32017-05-24 12:04:13 -070045static constexpr size_t kMaxMethodIds = 65535;
Mathieu Chartier9e050df2017-08-09 10:05:47 -070046static constexpr bool kDebugArgs = false;
Mathieu Chartierea650f32017-05-24 12:04:13 -070047
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080048using android::base::StringPrintf;
49
Andreas Gampee1459ae2016-06-29 09:36:30 -070050class Dex2oatTest : public Dex2oatEnvironmentTest {
51 public:
52 virtual void TearDown() OVERRIDE {
53 Dex2oatEnvironmentTest::TearDown();
54
55 output_ = "";
56 error_msg_ = "";
57 success_ = false;
58 }
59
60 protected:
Mathieu Chartier9e050df2017-08-09 10:05:47 -070061 int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
Andreas Gampef7882972017-03-20 16:35:24 -070062 const std::string& odex_location,
63 CompilerFilter::Filter filter,
64 std::string* error_msg,
65 const std::vector<std::string>& extra_args = {},
66 bool use_fd = false) {
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080067 std::unique_ptr<File> oat_file;
Andreas Gampee1459ae2016-06-29 09:36:30 -070068 std::vector<std::string> args;
Mathieu Chartier9e050df2017-08-09 10:05:47 -070069 // Add dex file args.
70 for (const std::string& dex_location : dex_locations) {
71 args.push_back("--dex-file=" + dex_location);
72 }
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080073 if (use_fd) {
74 oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
75 CHECK(oat_file != nullptr) << odex_location;
76 args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
Mathieu Chartier046854b2017-03-01 17:16:22 -080077 args.push_back("--oat-location=" + odex_location);
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080078 } else {
79 args.push_back("--oat-file=" + odex_location);
80 }
Andreas Gampee1459ae2016-06-29 09:36:30 -070081 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
82 args.push_back("--runtime-arg");
83 args.push_back("-Xnorelocate");
84
85 args.insert(args.end(), extra_args.begin(), extra_args.end());
86
Andreas Gampef7882972017-03-20 16:35:24 -070087 int status = Dex2Oat(args, error_msg);
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080088 if (oat_file != nullptr) {
Andreas Gampef7882972017-03-20 16:35:24 -070089 CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
Mathieu Chartier8bc343b2017-03-01 15:20:30 -080090 }
Andreas Gampef7882972017-03-20 16:35:24 -070091 return status;
92 }
Andreas Gampee1459ae2016-06-29 09:36:30 -070093
Andreas Gampe641a4732017-08-24 13:21:35 -070094 void GenerateOdexForTest(
95 const std::string& dex_location,
96 const std::string& odex_location,
97 CompilerFilter::Filter filter,
98 const std::vector<std::string>& extra_args = {},
99 bool expect_success = true,
100 bool use_fd = false) {
101 GenerateOdexForTest(dex_location,
102 odex_location,
103 filter,
104 extra_args,
105 expect_success,
106 use_fd,
107 [](const OatFile&) {});
108 }
109
110 template <typename T>
111 void GenerateOdexForTest(
112 const std::string& dex_location,
113 const std::string& odex_location,
114 CompilerFilter::Filter filter,
115 const std::vector<std::string>& extra_args,
116 bool expect_success,
117 bool use_fd,
118 T check_oat) {
Andreas Gampef7882972017-03-20 16:35:24 -0700119 std::string error_msg;
Mathieu Chartier9e050df2017-08-09 10:05:47 -0700120 int status = GenerateOdexForTestWithStatus({dex_location},
Andreas Gampef7882972017-03-20 16:35:24 -0700121 odex_location,
122 filter,
123 &error_msg,
124 extra_args,
125 use_fd);
126 bool success = (status == 0);
Andreas Gampee1459ae2016-06-29 09:36:30 -0700127 if (expect_success) {
Andreas Gampe2e8a2562017-01-18 20:39:02 -0800128 ASSERT_TRUE(success) << error_msg << std::endl << output_;
Andreas Gampee1459ae2016-06-29 09:36:30 -0700129
130 // Verify the odex file was generated as expected.
131 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
132 odex_location.c_str(),
133 nullptr,
134 nullptr,
135 false,
136 /*low_4gb*/false,
137 dex_location.c_str(),
138 &error_msg));
139 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
140
141 CheckFilter(filter, odex_file->GetCompilerFilter());
Calin Juravle1ce70852017-06-28 10:59:03 -0700142 check_oat(*(odex_file.get()));
Andreas Gampee1459ae2016-06-29 09:36:30 -0700143 } else {
144 ASSERT_FALSE(success) << output_;
145
146 error_msg_ = error_msg;
147
148 // Verify there's no loadable odex file.
149 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
150 odex_location.c_str(),
151 nullptr,
152 nullptr,
153 false,
154 /*low_4gb*/false,
155 dex_location.c_str(),
156 &error_msg));
157 ASSERT_TRUE(odex_file.get() == nullptr);
158 }
159 }
160
Calin Juravle1ccf6132017-08-02 17:46:53 -0700161 // Check the input compiler filter against the generated oat file's filter. May be overridden
Andreas Gampee1459ae2016-06-29 09:36:30 -0700162 // in subclasses when equality is not expected.
163 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
164 EXPECT_EQ(expected, actual);
165 }
166
Andreas Gampef7882972017-03-20 16:35:24 -0700167 int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700168 Runtime* runtime = Runtime::Current();
169
170 const std::vector<gc::space::ImageSpace*>& image_spaces =
171 runtime->GetHeap()->GetBootImageSpaces();
172 if (image_spaces.empty()) {
173 *error_msg = "No image location found for Dex2Oat.";
174 return false;
175 }
176 std::string image_location = image_spaces[0]->GetImageLocation();
177
178 std::vector<std::string> argv;
179 argv.push_back(runtime->GetCompilerExecutable());
Calin Juravle1ccf6132017-08-02 17:46:53 -0700180
Nicolas Geoffray433b79a2017-01-30 20:54:45 +0000181 if (runtime->IsJavaDebuggable()) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700182 argv.push_back("--debuggable");
183 }
184 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
185
186 if (!runtime->IsVerificationEnabled()) {
Nicolas Geoffray49cda062017-04-21 13:08:25 +0100187 argv.push_back("--compiler-filter=assume-verified");
Andreas Gampee1459ae2016-06-29 09:36:30 -0700188 }
189
190 if (runtime->MustRelocateIfPossible()) {
191 argv.push_back("--runtime-arg");
192 argv.push_back("-Xrelocate");
193 } else {
194 argv.push_back("--runtime-arg");
195 argv.push_back("-Xnorelocate");
196 }
197
198 if (!kIsTargetBuild) {
199 argv.push_back("--host");
200 }
201
202 argv.push_back("--boot-image=" + image_location);
203
204 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
205 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
206
207 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
208
209 // We must set --android-root.
210 const char* android_root = getenv("ANDROID_ROOT");
211 CHECK(android_root != nullptr);
212 argv.push_back("--android-root=" + std::string(android_root));
213
Mathieu Chartier9e050df2017-08-09 10:05:47 -0700214 if (kDebugArgs) {
215 std::string all_args;
216 for (const std::string& arg : argv) {
217 all_args += arg + " ";
218 }
219 LOG(ERROR) << all_args;
220 }
221
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100222 int link[2];
Andreas Gampee1459ae2016-06-29 09:36:30 -0700223
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100224 if (pipe(link) == -1) {
225 return false;
226 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700227
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100228 pid_t pid = fork();
229 if (pid == -1) {
230 return false;
231 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700232
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100233 if (pid == 0) {
234 // We need dex2oat to actually log things.
235 setenv("ANDROID_LOG_TAGS", "*:d", 1);
236 dup2(link[1], STDERR_FILENO);
237 close(link[0]);
238 close(link[1]);
239 std::vector<const char*> c_args;
240 for (const std::string& str : argv) {
241 c_args.push_back(str.c_str());
Andreas Gampee1459ae2016-06-29 09:36:30 -0700242 }
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100243 c_args.push_back(nullptr);
244 execv(c_args[0], const_cast<char* const*>(c_args.data()));
245 exit(1);
Andreas Gampef7882972017-03-20 16:35:24 -0700246 UNREACHABLE();
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100247 } else {
248 close(link[1]);
249 char buffer[128];
250 memset(buffer, 0, 128);
251 ssize_t bytes_read = 0;
Andreas Gampee1459ae2016-06-29 09:36:30 -0700252
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100253 while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
254 output_ += std::string(buffer, bytes_read);
255 }
256 close(link[0]);
Andreas Gampef7882972017-03-20 16:35:24 -0700257 int status = -1;
Nicolas Geoffray56fe0f02016-06-30 15:07:46 +0100258 if (waitpid(pid, &status, 0) != -1) {
259 success_ = (status == 0);
260 }
Andreas Gampef7882972017-03-20 16:35:24 -0700261 return status;
Andreas Gampee1459ae2016-06-29 09:36:30 -0700262 }
Andreas Gampee1459ae2016-06-29 09:36:30 -0700263 }
264
265 std::string output_ = "";
266 std::string error_msg_ = "";
267 bool success_ = false;
268};
269
270class Dex2oatSwapTest : public Dex2oatTest {
271 protected:
272 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
273 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
274 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
275
Andreas Gampe7adeda82016-07-25 08:27:35 -0700276 Copy(GetTestDexFileName(), dex_location);
Andreas Gampee1459ae2016-06-29 09:36:30 -0700277
278 std::vector<std::string> copy(extra_args);
279
280 std::unique_ptr<ScratchFile> sf;
281 if (use_fd) {
282 sf.reset(new ScratchFile());
Andreas Gampe46ee31b2016-12-14 10:11:49 -0800283 copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
Andreas Gampee1459ae2016-06-29 09:36:30 -0700284 } else {
285 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
286 copy.push_back("--swap-file=" + swap_location);
287 }
288 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
289
290 CheckValidity();
291 ASSERT_TRUE(success_);
292 CheckResult(expect_use);
293 }
294
Andreas Gampe7adeda82016-07-25 08:27:35 -0700295 virtual std::string GetTestDexFileName() {
Vladimir Marko15357702017-02-09 10:37:31 +0000296 return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
Andreas Gampe7adeda82016-07-25 08:27:35 -0700297 }
298
299 virtual void CheckResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700300 if (kIsTargetBuild) {
301 CheckTargetResult(expect_use);
302 } else {
303 CheckHostResult(expect_use);
304 }
305 }
306
Andreas Gampe7adeda82016-07-25 08:27:35 -0700307 virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700308 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
309 // something for variants with file descriptor where we can control the lifetime of
310 // the swap file and thus take a look at it.
311 }
312
Andreas Gampe7adeda82016-07-25 08:27:35 -0700313 virtual void CheckHostResult(bool expect_use) {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700314 if (!kIsTargetBuild) {
315 if (expect_use) {
316 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
317 << output_;
318 } else {
319 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
320 << output_;
321 }
322 }
323 }
324
325 // Check whether the dex2oat run was really successful.
Andreas Gampe7adeda82016-07-25 08:27:35 -0700326 virtual void CheckValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700327 if (kIsTargetBuild) {
328 CheckTargetValidity();
329 } else {
330 CheckHostValidity();
331 }
332 }
333
Andreas Gampe7adeda82016-07-25 08:27:35 -0700334 virtual void CheckTargetValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700335 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
336 // something for variants with file descriptor where we can control the lifetime of
337 // the swap file and thus take a look at it.
338 }
339
340 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
Andreas Gampe7adeda82016-07-25 08:27:35 -0700341 virtual void CheckHostValidity() {
Andreas Gampee1459ae2016-06-29 09:36:30 -0700342 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
343 }
344};
345
346TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
347 RunTest(false /* use_fd */, false /* expect_use */);
348 RunTest(true /* use_fd */, false /* expect_use */);
349}
350
351TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
352 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
353 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
354}
355
356TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
357 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
358 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
359}
360
361TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
362 RunTest(false /* use_fd */,
363 true /* expect_use */,
364 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
365 RunTest(true /* use_fd */,
366 true /* expect_use */,
367 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
368}
369
Andreas Gampe7adeda82016-07-25 08:27:35 -0700370class Dex2oatSwapUseTest : public Dex2oatSwapTest {
371 protected:
372 void CheckHostResult(bool expect_use) OVERRIDE {
373 if (!kIsTargetBuild) {
374 if (expect_use) {
375 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
376 << output_;
377 } else {
378 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
379 << output_;
380 }
381 }
382 }
383
384 std::string GetTestDexFileName() OVERRIDE {
385 // Use Statics as it has a handful of functions.
386 return CommonRuntimeTest::GetTestDexFileName("Statics");
387 }
388
389 void GrabResult1() {
390 if (!kIsTargetBuild) {
391 native_alloc_1_ = ParseNativeAlloc();
392 swap_1_ = ParseSwap(false /* expected */);
393 } else {
394 native_alloc_1_ = std::numeric_limits<size_t>::max();
395 swap_1_ = 0;
396 }
397 }
398
399 void GrabResult2() {
400 if (!kIsTargetBuild) {
401 native_alloc_2_ = ParseNativeAlloc();
402 swap_2_ = ParseSwap(true /* expected */);
403 } else {
404 native_alloc_2_ = 0;
405 swap_2_ = std::numeric_limits<size_t>::max();
406 }
407 }
408
409 private:
410 size_t ParseNativeAlloc() {
411 std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
412 std::smatch native_alloc_match;
413 bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
414 if (!found) {
415 EXPECT_TRUE(found);
416 return 0;
417 }
418 if (native_alloc_match.size() != 2U) {
419 EXPECT_EQ(native_alloc_match.size(), 2U);
420 return 0;
421 }
422
423 std::istringstream stream(native_alloc_match[1].str());
424 size_t value;
425 stream >> value;
426
427 return value;
428 }
429
430 size_t ParseSwap(bool expected) {
431 std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
432 std::smatch swap_match;
433 bool found = std::regex_search(output_, swap_match, swap_regex);
434 if (found != expected) {
435 EXPECT_EQ(expected, found);
436 return 0;
437 }
438
439 if (!found) {
440 return 0;
441 }
442
443 if (swap_match.size() != 2U) {
444 EXPECT_EQ(swap_match.size(), 2U);
445 return 0;
446 }
447
448 std::istringstream stream(swap_match[1].str());
449 size_t value;
450 stream >> value;
451
452 return value;
453 }
454
455 protected:
456 size_t native_alloc_1_;
457 size_t native_alloc_2_;
458
459 size_t swap_1_;
460 size_t swap_2_;
461};
462
463TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
Andreas Gampef4a67fd2017-05-04 09:55:36 -0700464 // Native memory usage isn't correctly tracked under sanitization.
465 TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
466
Vladimir Marko57070da2017-02-14 16:16:30 +0000467 // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
Roland Levillain19772bf2017-02-16 11:28:10 +0000468 // hold true on some x86 systems; disable this test while we
469 // investigate (b/29259363).
470 TEST_DISABLED_FOR_X86();
Vladimir Marko57070da2017-02-14 16:16:30 +0000471
Andreas Gampe7adeda82016-07-25 08:27:35 -0700472 RunTest(false /* use_fd */,
473 false /* expect_use */);
474 GrabResult1();
475 std::string output_1 = output_;
476
477 output_ = "";
478
479 RunTest(false /* use_fd */,
480 true /* expect_use */,
481 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
482 GrabResult2();
483 std::string output_2 = output_;
484
485 if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
486 EXPECT_LT(native_alloc_2_, native_alloc_1_);
487 EXPECT_LT(swap_1_, swap_2_);
488
489 LOG(ERROR) << output_1;
490 LOG(ERROR) << output_2;
491 }
492}
493
Andreas Gampe67f02822016-06-24 21:05:23 -0700494class Dex2oatVeryLargeTest : public Dex2oatTest {
495 protected:
496 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
497 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
498 // Ignore, we'll do our own checks.
499 }
500
501 void RunTest(CompilerFilter::Filter filter,
502 bool expect_large,
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700503 bool expect_downgrade,
Andreas Gampe67f02822016-06-24 21:05:23 -0700504 const std::vector<std::string>& extra_args = {}) {
505 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
506 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700507 std::string app_image_file = GetScratchDir() + "/Test.art";
Andreas Gampe67f02822016-06-24 21:05:23 -0700508
509 Copy(GetDexSrc1(), dex_location);
510
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700511 std::vector<std::string> new_args(extra_args);
512 new_args.push_back("--app-image-file=" + app_image_file);
513 GenerateOdexForTest(dex_location, odex_location, filter, new_args);
Andreas Gampe67f02822016-06-24 21:05:23 -0700514
515 CheckValidity();
516 ASSERT_TRUE(success_);
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700517 CheckResult(dex_location,
518 odex_location,
519 app_image_file,
520 filter,
521 expect_large,
522 expect_downgrade);
Andreas Gampe67f02822016-06-24 21:05:23 -0700523 }
524
525 void CheckResult(const std::string& dex_location,
526 const std::string& odex_location,
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700527 const std::string& app_image_file,
Andreas Gampe67f02822016-06-24 21:05:23 -0700528 CompilerFilter::Filter filter,
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700529 bool expect_large,
530 bool expect_downgrade) {
531 if (expect_downgrade) {
532 EXPECT_TRUE(expect_large);
533 }
Andreas Gampe67f02822016-06-24 21:05:23 -0700534 // Host/target independent checks.
535 std::string error_msg;
536 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
537 odex_location.c_str(),
538 nullptr,
539 nullptr,
540 false,
541 /*low_4gb*/false,
542 dex_location.c_str(),
543 &error_msg));
544 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700545 EXPECT_GT(app_image_file.length(), 0u);
546 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file.c_str()));
Andreas Gampe67f02822016-06-24 21:05:23 -0700547 if (expect_large) {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700548 // Note: we cannot check the following
549 // EXPECT_FALSE(CompilerFilter::IsAotCompilationEnabled(odex_file->GetCompilerFilter()));
Andreas Gampe67f02822016-06-24 21:05:23 -0700550 // The reason is that the filter override currently happens when the dex files are
551 // loaded in dex2oat, which is after the oat file has been started. Thus, the header
552 // store cannot be changed, and the original filter is set in stone.
553
554 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
555 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
556 ASSERT_TRUE(dex_file != nullptr);
557 uint32_t class_def_count = dex_file->NumClassDefs();
558 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
559 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
560 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
561 EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
562 }
563 }
564
565 // If the input filter was "below," it should have been used.
Nicolas Geoffray49cda062017-04-21 13:08:25 +0100566 if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
Andreas Gampe67f02822016-06-24 21:05:23 -0700567 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
568 }
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700569
570 // If expect large, make sure the app image isn't generated or is empty.
571 if (file != nullptr) {
572 EXPECT_EQ(file->GetLength(), 0u);
573 }
Andreas Gampe67f02822016-06-24 21:05:23 -0700574 } else {
575 EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700576 ASSERT_TRUE(file != nullptr) << app_image_file;
577 EXPECT_GT(file->GetLength(), 0u);
Andreas Gampe67f02822016-06-24 21:05:23 -0700578 }
579
580 // Host/target dependent checks.
581 if (kIsTargetBuild) {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700582 CheckTargetResult(expect_downgrade);
Andreas Gampe67f02822016-06-24 21:05:23 -0700583 } else {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700584 CheckHostResult(expect_downgrade);
Andreas Gampe67f02822016-06-24 21:05:23 -0700585 }
586 }
587
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700588 void CheckTargetResult(bool expect_downgrade ATTRIBUTE_UNUSED) {
Andreas Gampe67f02822016-06-24 21:05:23 -0700589 // TODO: Ignore for now. May do something for fd things.
590 }
591
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700592 void CheckHostResult(bool expect_downgrade) {
Andreas Gampe67f02822016-06-24 21:05:23 -0700593 if (!kIsTargetBuild) {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700594 if (expect_downgrade) {
595 EXPECT_NE(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
Andreas Gampe67f02822016-06-24 21:05:23 -0700596 } else {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700597 EXPECT_EQ(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
Andreas Gampe67f02822016-06-24 21:05:23 -0700598 }
599 }
600 }
601
602 // Check whether the dex2oat run was really successful.
603 void CheckValidity() {
604 if (kIsTargetBuild) {
605 CheckTargetValidity();
606 } else {
607 CheckHostValidity();
608 }
609 }
610
611 void CheckTargetValidity() {
612 // TODO: Ignore for now.
613 }
614
615 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
616 void CheckHostValidity() {
617 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
618 }
619};
620
621TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700622 RunTest(CompilerFilter::kAssumeVerified, false, false);
623 RunTest(CompilerFilter::kExtract, false, false);
624 RunTest(CompilerFilter::kQuicken, false, false);
625 RunTest(CompilerFilter::kSpeed, false, false);
Andreas Gampe67f02822016-06-24 21:05:23 -0700626
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700627 RunTest(CompilerFilter::kAssumeVerified, false, false, { "--very-large-app-threshold=10000000" });
628 RunTest(CompilerFilter::kExtract, false, false, { "--very-large-app-threshold=10000000" });
629 RunTest(CompilerFilter::kQuicken, false, false, { "--very-large-app-threshold=10000000" });
630 RunTest(CompilerFilter::kSpeed, false, false, { "--very-large-app-threshold=10000000" });
Andreas Gampe67f02822016-06-24 21:05:23 -0700631}
632
633TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700634 RunTest(CompilerFilter::kAssumeVerified, true, false, { "--very-large-app-threshold=100" });
635 RunTest(CompilerFilter::kExtract, true, false, { "--very-large-app-threshold=100" });
636 RunTest(CompilerFilter::kQuicken, true, true, { "--very-large-app-threshold=100" });
637 RunTest(CompilerFilter::kSpeed, true, true, { "--very-large-app-threshold=100" });
Andreas Gampe67f02822016-06-24 21:05:23 -0700638}
639
Mathieu Chartier97ab5e32017-02-22 13:35:44 -0800640// Regressin test for b/35665292.
641TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
642 // Test that dex2oat doesn't crash with speed-profile but no input profile.
Mathieu Chartier8cce65a2017-08-17 00:06:39 -0700643 RunTest(CompilerFilter::kSpeedProfile, false, false);
Mathieu Chartier97ab5e32017-02-22 13:35:44 -0800644}
645
Jeff Hao608f2ce2016-10-19 11:17:11 -0700646class Dex2oatLayoutTest : public Dex2oatTest {
647 protected:
648 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
649 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
650 // Ignore, we'll do our own checks.
651 }
652
Jeff Hao41fba6a2016-11-28 11:53:33 -0800653 // Emits a profile with a single dex file with the given location and a single class index of 1.
654 void GenerateProfile(const std::string& test_profile,
655 const std::string& dex_location,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800656 size_t num_classes,
Jeff Hao41fba6a2016-11-28 11:53:33 -0800657 uint32_t checksum) {
658 int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
659 CHECK_GE(profile_test_fd, 0);
660
661 ProfileCompilationInfo info;
662 std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800663 for (size_t i = 0; i < num_classes; ++i) {
Mathieu Chartierea650f32017-05-24 12:04:13 -0700664 info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i), kMaxMethodIds);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800665 }
Jeff Hao41fba6a2016-11-28 11:53:33 -0800666 bool result = info.Save(profile_test_fd);
667 close(profile_test_fd);
668 ASSERT_TRUE(result);
669 }
670
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800671 void CompileProfileOdex(const std::string& dex_location,
672 const std::string& odex_location,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800673 const std::string& app_image_file_name,
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800674 bool use_fd,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800675 size_t num_profile_classes,
Nicolas Geoffray97fa9922017-03-09 13:13:25 +0000676 const std::vector<std::string>& extra_args = {},
677 bool expect_success = true) {
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800678 const std::string profile_location = GetScratchDir() + "/primary.prof";
Jeff Hao41fba6a2016-11-28 11:53:33 -0800679 const char* location = dex_location.c_str();
680 std::string error_msg;
681 std::vector<std::unique_ptr<const DexFile>> dex_files;
Nicolas Geoffray095c6c92017-10-19 13:59:55 +0100682 ASSERT_TRUE(DexFileLoader::Open(
683 location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
Jeff Hao41fba6a2016-11-28 11:53:33 -0800684 EXPECT_EQ(dex_files.size(), 1U);
685 std::unique_ptr<const DexFile>& dex_file = dex_files[0];
Mathieu Chartier046854b2017-03-01 17:16:22 -0800686 GenerateProfile(profile_location,
687 dex_location,
688 num_profile_classes,
689 dex_file->GetLocationChecksum());
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800690 std::vector<std::string> copy(extra_args);
691 copy.push_back("--profile-file=" + profile_location);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800692 std::unique_ptr<File> app_image_file;
693 if (!app_image_file_name.empty()) {
694 if (use_fd) {
695 app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
696 copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
697 } else {
698 copy.push_back("--app-image-file=" + app_image_file_name);
699 }
700 }
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800701 GenerateOdexForTest(dex_location,
702 odex_location,
703 CompilerFilter::kSpeedProfile,
704 copy,
Nicolas Geoffray97fa9922017-03-09 13:13:25 +0000705 expect_success,
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800706 use_fd);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800707 if (app_image_file != nullptr) {
708 ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
709 }
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800710 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700711
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100712 uint64_t GetImageObjectSectionSize(const std::string& image_file_name) {
Mathieu Chartier046854b2017-03-01 17:16:22 -0800713 EXPECT_FALSE(image_file_name.empty());
714 std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
715 CHECK(file != nullptr);
716 ImageHeader image_header;
717 const bool success = file->ReadFully(&image_header, sizeof(image_header));
718 CHECK(success);
719 CHECK(image_header.IsValid());
720 ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100721 return image_header.GetObjectsSection().Size();
Mathieu Chartier046854b2017-03-01 17:16:22 -0800722 }
723
724 void RunTest(bool app_image) {
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800725 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
726 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
Mathieu Chartier046854b2017-03-01 17:16:22 -0800727 std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800728 Copy(GetDexSrc2(), dex_location);
729
Mathieu Chartier046854b2017-03-01 17:16:22 -0800730 uint64_t image_file_empty_profile = 0;
731 if (app_image) {
732 CompileProfileOdex(dex_location,
733 odex_location,
734 app_image_file,
735 /* use_fd */ false,
736 /* num_profile_classes */ 0);
737 CheckValidity();
738 ASSERT_TRUE(success_);
739 // Don't check the result since CheckResult relies on the class being in the profile.
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100740 image_file_empty_profile = GetImageObjectSectionSize(app_image_file);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800741 EXPECT_GT(image_file_empty_profile, 0u);
742 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700743
Mathieu Chartier046854b2017-03-01 17:16:22 -0800744 // Small profile.
745 CompileProfileOdex(dex_location,
746 odex_location,
747 app_image_file,
748 /* use_fd */ false,
749 /* num_profile_classes */ 1);
Jeff Hao608f2ce2016-10-19 11:17:11 -0700750 CheckValidity();
751 ASSERT_TRUE(success_);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800752 CheckResult(dex_location, odex_location, app_image_file);
753
754 if (app_image) {
755 // Test that the profile made a difference by adding more classes.
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100756 const uint64_t image_file_small_profile = GetImageObjectSectionSize(app_image_file);
757 ASSERT_LT(image_file_empty_profile, image_file_small_profile);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800758 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700759 }
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800760
761 void RunTestVDex() {
762 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
763 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
764 std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
Mathieu Chartier046854b2017-03-01 17:16:22 -0800765 std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800766 Copy(GetDexSrc2(), dex_location);
767
768 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
769 CHECK(vdex_file1 != nullptr) << vdex_location;
770 ScratchFile vdex_file2;
771 {
772 std::string input_vdex = "--input-vdex-fd=-1";
773 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
774 CompileProfileOdex(dex_location,
775 odex_location,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800776 app_image_file_name,
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800777 /* use_fd */ true,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800778 /* num_profile_classes */ 1,
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800779 { input_vdex, output_vdex });
780 EXPECT_GT(vdex_file1->GetLength(), 0u);
781 }
782 {
Nicolas Geoffray97fa9922017-03-09 13:13:25 +0000783 // Test that vdex and dexlayout fail gracefully.
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800784 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
785 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
786 CompileProfileOdex(dex_location,
787 odex_location,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800788 app_image_file_name,
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800789 /* use_fd */ true,
Mathieu Chartier046854b2017-03-01 17:16:22 -0800790 /* num_profile_classes */ 1,
Nicolas Geoffray97fa9922017-03-09 13:13:25 +0000791 { input_vdex, output_vdex },
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100792 /* expect_success */ true);
793 EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800794 }
795 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
796 CheckValidity();
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100797 ASSERT_TRUE(success_);
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800798 }
799
Mathieu Chartier046854b2017-03-01 17:16:22 -0800800 void CheckResult(const std::string& dex_location,
801 const std::string& odex_location,
802 const std::string& app_image_file_name) {
Jeff Hao608f2ce2016-10-19 11:17:11 -0700803 // Host/target independent checks.
804 std::string error_msg;
805 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
806 odex_location.c_str(),
807 nullptr,
808 nullptr,
809 false,
810 /*low_4gb*/false,
811 dex_location.c_str(),
812 &error_msg));
813 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
814
Jeff Hao042e8982016-10-19 11:17:11 -0700815 const char* location = dex_location.c_str();
816 std::vector<std::unique_ptr<const DexFile>> dex_files;
Nicolas Geoffray095c6c92017-10-19 13:59:55 +0100817 ASSERT_TRUE(DexFileLoader::Open(
818 location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
Jeff Hao042e8982016-10-19 11:17:11 -0700819 EXPECT_EQ(dex_files.size(), 1U);
820 std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
821
Jeff Hao608f2ce2016-10-19 11:17:11 -0700822 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
Jeff Hao042e8982016-10-19 11:17:11 -0700823 std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
824 ASSERT_TRUE(new_dex_file != nullptr);
825 uint32_t class_def_count = new_dex_file->NumClassDefs();
Jeff Hao608f2ce2016-10-19 11:17:11 -0700826 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
Jeff Hao042e8982016-10-19 11:17:11 -0700827 ASSERT_GE(class_def_count, 2U);
828
Mathieu Chartier24066ec2017-10-21 16:01:08 -0700829 // Make sure the indexes stay the same.
Jeff Hao042e8982016-10-19 11:17:11 -0700830 std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
831 std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
832 std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
833 std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
Mathieu Chartier24066ec2017-10-21 16:01:08 -0700834 EXPECT_EQ(old_class0, new_class0);
835 EXPECT_EQ(old_class1, new_class1);
Jeff Hao608f2ce2016-10-19 11:17:11 -0700836 }
837
Jeff Haoc155b052017-01-17 17:43:29 -0800838 EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800839
840 if (!app_image_file_name.empty()) {
841 // Go peek at the image header to make sure it was large enough to contain the class.
842 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
843 ImageHeader image_header;
844 bool success = file->ReadFully(&image_header, sizeof(image_header));
845 ASSERT_TRUE(success);
846 ASSERT_TRUE(image_header.IsValid());
Vladimir Markocd87c3e2017-09-05 13:11:57 +0100847 EXPECT_GT(image_header.GetObjectsSection().Size(), 0u);
Mathieu Chartier046854b2017-03-01 17:16:22 -0800848 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700849 }
850
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800851 // Check whether the dex2oat run was really successful.
852 void CheckValidity() {
853 if (kIsTargetBuild) {
854 CheckTargetValidity();
855 } else {
856 CheckHostValidity();
Jeff Hao608f2ce2016-10-19 11:17:11 -0700857 }
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800858 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700859
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800860 void CheckTargetValidity() {
861 // TODO: Ignore for now.
862 }
Jeff Hao608f2ce2016-10-19 11:17:11 -0700863
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800864 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
865 void CheckHostValidity() {
866 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
867 }
868};
Jeff Hao608f2ce2016-10-19 11:17:11 -0700869
870TEST_F(Dex2oatLayoutTest, TestLayout) {
Mathieu Chartier046854b2017-03-01 17:16:22 -0800871 RunTest(/* app-image */ false);
872}
873
874TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
875 RunTest(/* app-image */ true);
Jeff Hao608f2ce2016-10-19 11:17:11 -0700876}
877
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800878TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
Mathieu Chartier2c4b0842017-12-13 11:49:51 -0800879 // Disabled until figure out running compact dex + DexLayout causes quickening errors.
880 TEST_DISABLED_FOR_COMPACT_DEX();
Mathieu Chartier8bc343b2017-03-01 15:20:30 -0800881 RunTestVDex();
882}
883
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100884class Dex2oatUnquickenTest : public Dex2oatTest {
885 protected:
886 void RunUnquickenMultiDex() {
887 std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar";
888 std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex";
889 std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex";
890 Copy(GetTestDexFileName("MultiDex"), dex_location);
891
892 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
893 CHECK(vdex_file1 != nullptr) << vdex_location;
894 // Quicken the dex file into a vdex file.
895 {
896 std::string input_vdex = "--input-vdex-fd=-1";
897 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
898 GenerateOdexForTest(dex_location,
899 odex_location,
900 CompilerFilter::kQuicken,
901 { input_vdex, output_vdex },
902 /* expect_success */ true,
903 /* use_fd */ true);
904 EXPECT_GT(vdex_file1->GetLength(), 0u);
905 }
906 // Unquicken by running the verify compiler filter on the vdex file.
907 {
908 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
909 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
910 GenerateOdexForTest(dex_location,
911 odex_location,
912 CompilerFilter::kVerify,
913 { input_vdex, output_vdex },
914 /* expect_success */ true,
915 /* use_fd */ true);
916 }
917 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
918 CheckResult(dex_location, odex_location);
919 ASSERT_TRUE(success_);
920 }
921
922 void CheckResult(const std::string& dex_location, const std::string& odex_location) {
923 std::string error_msg;
924 std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
925 odex_location.c_str(),
926 nullptr,
927 nullptr,
928 false,
929 /*low_4gb*/false,
930 dex_location.c_str(),
931 &error_msg));
932 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
933 ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u);
934
935 // Iterate over the dex files and ensure there is no quickened instruction.
936 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
937 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
938 for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
939 const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
940 const uint8_t* class_data = dex_file->GetClassData(class_def);
941 if (class_data != nullptr) {
942 for (ClassDataItemIterator class_it(*dex_file, class_data);
943 class_it.HasNext();
944 class_it.Next()) {
945 if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
Mathieu Chartier0021feb2017-11-07 00:08:52 -0800946 for (const DexInstructionPcPair& inst :
Mathieu Chartier73f21d42018-01-02 14:26:50 -0800947 CodeItemInstructionAccessor(dex_file.get(), class_it.GetMethodCodeItem())) {
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100948 ASSERT_FALSE(inst->IsQuickened());
949 }
950 }
951 }
952 }
953 }
954 }
955 }
956};
957
958TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) {
Mathieu Chartier532246e2017-12-15 16:44:21 -0800959 // Disabled until figure out running compact dex + DexLayout causes quickening errors.
960 TEST_DISABLED_FOR_COMPACT_DEX();
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100961 RunUnquickenMultiDex();
962}
963
Andreas Gampe2e8a2562017-01-18 20:39:02 -0800964class Dex2oatWatchdogTest : public Dex2oatTest {
965 protected:
966 void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
967 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
968 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
969
970 Copy(GetTestDexFileName(), dex_location);
971
972 std::vector<std::string> copy(extra_args);
973
974 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
975 copy.push_back("--swap-file=" + swap_location);
Andreas Gampe22fa3762017-10-23 20:58:12 -0700976 copy.push_back("-j512"); // Excessive idle threads just slow down dex2oat.
Andreas Gampe2e8a2562017-01-18 20:39:02 -0800977 GenerateOdexForTest(dex_location,
978 odex_location,
979 CompilerFilter::kSpeed,
980 copy,
981 expect_success);
982 }
983
984 std::string GetTestDexFileName() {
985 return GetDexSrc1();
986 }
987};
988
989TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
990 // Check with default.
991 RunTest(true);
992
993 // Check with ten minutes.
994 RunTest(true, { "--watchdog-timeout=600000" });
995}
996
997TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
Roland Levillain68db2252017-08-14 12:48:47 +0100998 TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND(); // b/63052624
Andreas Gampe21f9cb82017-12-27 08:43:08 -0800999 TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // b/63052624
Andreas Gampe2e8a2562017-01-18 20:39:02 -08001000 // Check with ten milliseconds.
1001 RunTest(false, { "--watchdog-timeout=10" });
1002}
1003
Andreas Gampef7882972017-03-20 16:35:24 -07001004class Dex2oatReturnCodeTest : public Dex2oatTest {
1005 protected:
1006 int RunTest(const std::vector<std::string>& extra_args = {}) {
1007 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
1008 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
1009
1010 Copy(GetTestDexFileName(), dex_location);
1011
1012 std::string error_msg;
Mathieu Chartier9e050df2017-08-09 10:05:47 -07001013 return GenerateOdexForTestWithStatus({dex_location},
Andreas Gampef7882972017-03-20 16:35:24 -07001014 odex_location,
1015 CompilerFilter::kSpeed,
1016 &error_msg,
1017 extra_args);
1018 }
1019
1020 std::string GetTestDexFileName() {
1021 return GetDexSrc1();
1022 }
1023};
1024
1025TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) {
Andreas Gampefd80b172017-04-26 22:25:31 -07001026 TEST_DISABLED_FOR_MEMORY_TOOL(); // b/19100793
Andreas Gampef7882972017-03-20 16:35:24 -07001027 int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" });
1028 EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_;
1029}
1030
Calin Juravle1ce70852017-06-28 10:59:03 -07001031class Dex2oatClassLoaderContextTest : public Dex2oatTest {
1032 protected:
1033 void RunTest(const char* class_loader_context,
1034 const char* expected_classpath_key,
1035 bool expected_success,
1036 bool use_second_source = false) {
1037 std::string dex_location = GetUsedDexLocation();
1038 std::string odex_location = GetUsedOatLocation();
1039
1040 Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location);
1041
1042 std::string error_msg;
1043 std::vector<std::string> extra_args;
1044 if (class_loader_context != nullptr) {
1045 extra_args.push_back(std::string("--class-loader-context=") + class_loader_context);
1046 }
1047 auto check_oat = [expected_classpath_key](const OatFile& oat_file) {
1048 ASSERT_TRUE(expected_classpath_key != nullptr);
1049 const char* classpath = oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey);
1050 ASSERT_TRUE(classpath != nullptr);
1051 ASSERT_STREQ(expected_classpath_key, classpath);
1052 };
1053
1054 GenerateOdexForTest(dex_location,
1055 odex_location,
1056 CompilerFilter::kQuicken,
1057 extra_args,
1058 expected_success,
1059 /*use_fd*/ false,
1060 check_oat);
1061 }
1062
1063 std::string GetUsedDexLocation() {
1064 return GetScratchDir() + "/Context.jar";
1065 }
1066
1067 std::string GetUsedOatLocation() {
1068 return GetOdexDir() + "/Context.odex";
1069 }
1070
Calin Juravle7b0648a2017-07-07 18:40:50 -07001071 const char* kEmptyClassPathKey = "PCL[]";
Calin Juravle1ce70852017-06-28 10:59:03 -07001072};
1073
1074TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) {
1075 RunTest("Invalid[]", /*expected_classpath_key*/ nullptr, /*expected_success*/ false);
1076}
1077
1078TEST_F(Dex2oatClassLoaderContextTest, EmptyContext) {
1079 RunTest("PCL[]", kEmptyClassPathKey, /*expected_success*/ true);
1080}
1081
1082TEST_F(Dex2oatClassLoaderContextTest, SpecialContext) {
1083 RunTest(OatFile::kSpecialSharedLibrary,
1084 OatFile::kSpecialSharedLibrary,
1085 /*expected_success*/ true);
1086}
1087
1088TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) {
1089 std::string context = "PCL[" + GetUsedDexLocation() + "]";
1090 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1091}
1092
1093TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) {
1094 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested");
Calin Juravle1ce70852017-06-28 10:59:03 -07001095
1096 std::string context = "PCL[" + dex_files[0]->GetLocation() + "]";
Calin Juravle7b0648a2017-07-07 18:40:50 -07001097 std::string expected_classpath_key = "PCL[" +
1098 dex_files[0]->GetLocation() + "*" + std::to_string(dex_files[0]->GetLocationChecksum()) + "]";
Calin Juravle1ce70852017-06-28 10:59:03 -07001099 RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1100}
1101
1102TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFiles) {
1103 std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
1104 Copy(GetStrippedDexSrc1(), stripped_classpath);
1105
1106 std::string context = "PCL[" + stripped_classpath + "]";
1107 // Expect an empty context because stripped dex files cannot be open.
Calin Juravle7b0648a2017-07-07 18:40:50 -07001108 RunTest(context.c_str(), kEmptyClassPathKey , /*expected_success*/ true);
Calin Juravle1ce70852017-06-28 10:59:03 -07001109}
1110
1111TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) {
1112 std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
1113 std::string odex_for_classpath = GetOdexDir() + "/stripped_classpath.odex";
1114
1115 Copy(GetDexSrc1(), stripped_classpath);
1116
1117 GenerateOdexForTest(stripped_classpath,
1118 odex_for_classpath,
1119 CompilerFilter::kQuicken,
1120 {},
1121 true);
1122
1123 // Strip the dex file
1124 Copy(GetStrippedDexSrc1(), stripped_classpath);
1125
1126 std::string context = "PCL[" + stripped_classpath + "]";
Calin Juravle7b0648a2017-07-07 18:40:50 -07001127 std::string expected_classpath_key;
Calin Juravle1ce70852017-06-28 10:59:03 -07001128 {
1129 // Open the oat file to get the expected classpath.
1130 OatFileAssistant oat_file_assistant(stripped_classpath.c_str(), kRuntimeISA, false);
1131 std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
1132 std::vector<std::unique_ptr<const DexFile>> oat_dex_files =
1133 OatFileAssistant::LoadDexFiles(*oat_file, stripped_classpath.c_str());
Calin Juravle7b0648a2017-07-07 18:40:50 -07001134 expected_classpath_key = "PCL[";
1135 for (size_t i = 0; i < oat_dex_files.size(); i++) {
1136 if (i > 0) {
1137 expected_classpath_key + ":";
1138 }
1139 expected_classpath_key += oat_dex_files[i]->GetLocation() + "*" +
1140 std::to_string(oat_dex_files[i]->GetLocationChecksum());
1141 }
1142 expected_classpath_key += "]";
Calin Juravle1ce70852017-06-28 10:59:03 -07001143 }
1144
1145 RunTest(context.c_str(),
Calin Juravle7b0648a2017-07-07 18:40:50 -07001146 expected_classpath_key.c_str(),
Calin Juravle1ce70852017-06-28 10:59:03 -07001147 /*expected_success*/ true,
1148 /*use_second_source*/ true);
1149}
1150
1151TEST_F(Dex2oatClassLoaderContextTest, ContextWithNotExistentDexFiles) {
1152 std::string context = "PCL[does_not_exists.dex]";
1153 // Expect an empty context because stripped dex files cannot be open.
1154 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1155}
1156
Calin Juravlec79470d2017-07-12 17:37:42 -07001157TEST_F(Dex2oatClassLoaderContextTest, ChainContext) {
1158 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1159 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1160
1161 std::string context = "PCL[" + GetTestDexFileName("Nested") + "];" +
1162 "DLC[" + GetTestDexFileName("MultiDex") + "]";
1163 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "];" +
1164 "DLC[" + CreateClassPathWithChecksums(dex_files2) + "]";
1165
1166 RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1167}
1168
Mathieu Chartier9e050df2017-08-09 10:05:47 -07001169class Dex2oatDeterminism : public Dex2oatTest {};
1170
1171TEST_F(Dex2oatDeterminism, UnloadCompile) {
1172 if (!kUseReadBarrier &&
1173 gc::kCollectorTypeDefault != gc::kCollectorTypeCMS &&
1174 gc::kCollectorTypeDefault != gc::kCollectorTypeMS) {
1175 LOG(INFO) << "Test requires determinism support.";
1176 return;
1177 }
1178 Runtime* const runtime = Runtime::Current();
1179 std::string out_dir = GetScratchDir();
1180 const std::string base_oat_name = out_dir + "/base.oat";
1181 const std::string base_vdex_name = out_dir + "/base.vdex";
1182 const std::string unload_oat_name = out_dir + "/unload.oat";
1183 const std::string unload_vdex_name = out_dir + "/unload.vdex";
1184 const std::string no_unload_oat_name = out_dir + "/nounload.oat";
1185 const std::string no_unload_vdex_name = out_dir + "/nounload.vdex";
1186 const std::string app_image_name = out_dir + "/unload.art";
1187 std::string error_msg;
1188 const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces();
1189 ASSERT_GT(spaces.size(), 0u);
1190 const std::string image_location = spaces[0]->GetImageLocation();
1191 // Without passing in an app image, it will unload in between compilations.
1192 const int res = GenerateOdexForTestWithStatus(
1193 GetLibCoreDexFileNames(),
1194 base_oat_name,
1195 CompilerFilter::Filter::kQuicken,
1196 &error_msg,
1197 {"--force-determinism", "--avoid-storing-invocation"});
1198 EXPECT_EQ(res, 0);
1199 Copy(base_oat_name, unload_oat_name);
1200 Copy(base_vdex_name, unload_vdex_name);
1201 std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
1202 std::unique_ptr<File> unload_vdex(OS::OpenFileForReading(unload_vdex_name.c_str()));
1203 ASSERT_TRUE(unload_oat != nullptr);
1204 ASSERT_TRUE(unload_vdex != nullptr);
1205 EXPECT_GT(unload_oat->GetLength(), 0u);
1206 EXPECT_GT(unload_vdex->GetLength(), 0u);
1207 // Regenerate with an app image to disable the dex2oat unloading and verify that the output is
1208 // the same.
1209 const int res2 = GenerateOdexForTestWithStatus(
1210 GetLibCoreDexFileNames(),
1211 base_oat_name,
1212 CompilerFilter::Filter::kQuicken,
1213 &error_msg,
1214 {"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name});
1215 EXPECT_EQ(res2, 0);
1216 Copy(base_oat_name, no_unload_oat_name);
1217 Copy(base_vdex_name, no_unload_vdex_name);
1218 std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
1219 std::unique_ptr<File> no_unload_vdex(OS::OpenFileForReading(no_unload_vdex_name.c_str()));
1220 ASSERT_TRUE(no_unload_oat != nullptr);
1221 ASSERT_TRUE(no_unload_vdex != nullptr);
1222 EXPECT_GT(no_unload_oat->GetLength(), 0u);
1223 EXPECT_GT(no_unload_vdex->GetLength(), 0u);
1224 // Verify that both of the files are the same (odex and vdex).
1225 EXPECT_EQ(unload_oat->GetLength(), no_unload_oat->GetLength());
1226 EXPECT_EQ(unload_vdex->GetLength(), no_unload_vdex->GetLength());
1227 EXPECT_EQ(unload_oat->Compare(no_unload_oat.get()), 0)
1228 << unload_oat_name << " " << no_unload_oat_name;
1229 EXPECT_EQ(unload_vdex->Compare(no_unload_vdex.get()), 0)
1230 << unload_vdex_name << " " << no_unload_vdex_name;
1231 // App image file.
1232 std::unique_ptr<File> app_image_file(OS::OpenFileForReading(app_image_name.c_str()));
1233 ASSERT_TRUE(app_image_file != nullptr);
1234 EXPECT_GT(app_image_file->GetLength(), 0u);
1235}
1236
Mathieu Chartier120aa282017-08-05 16:03:03 -07001237// Test that dexlayout section info is correctly written to the oat file for profile based
1238// compilation.
1239TEST_F(Dex2oatTest, LayoutSections) {
1240 using Hotness = ProfileCompilationInfo::MethodHotness;
1241 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1242 ScratchFile profile_file;
1243 // We can only layout method indices with code items, figure out which ones have this property
1244 // first.
1245 std::vector<uint16_t> methods;
1246 {
1247 const DexFile::TypeId* type_id = dex->FindTypeId("LManyMethods;");
1248 dex::TypeIndex type_idx = dex->GetIndexForTypeId(*type_id);
1249 const DexFile::ClassDef* class_def = dex->FindClassDef(type_idx);
1250 ClassDataItemIterator it(*dex, dex->GetClassData(*class_def));
1251 it.SkipAllFields();
1252 std::set<size_t> code_item_offsets;
Mathieu Chartierb7c273c2017-11-10 18:07:56 -08001253 for (; it.HasNextMethod(); it.Next()) {
Mathieu Chartier120aa282017-08-05 16:03:03 -07001254 const uint16_t method_idx = it.GetMemberIndex();
1255 const size_t code_item_offset = it.GetMethodCodeItemOffset();
1256 if (code_item_offsets.insert(code_item_offset).second) {
1257 // Unique code item, add the method index.
1258 methods.push_back(method_idx);
1259 }
1260 }
1261 DCHECK(!it.HasNext());
1262 }
1263 ASSERT_GE(methods.size(), 8u);
1264 std::vector<uint16_t> hot_methods = {methods[1], methods[3], methods[5]};
1265 std::vector<uint16_t> startup_methods = {methods[1], methods[2], methods[7]};
1266 std::vector<uint16_t> post_methods = {methods[0], methods[2], methods[6]};
1267 // Here, we build the profile from the method lists.
1268 ProfileCompilationInfo info;
1269 info.AddMethodsForDex(
1270 static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
1271 dex.get(),
1272 hot_methods.begin(),
1273 hot_methods.end());
1274 info.AddMethodsForDex(
1275 Hotness::kFlagStartup,
1276 dex.get(),
1277 startup_methods.begin(),
1278 startup_methods.end());
1279 info.AddMethodsForDex(
1280 Hotness::kFlagPostStartup,
1281 dex.get(),
1282 post_methods.begin(),
1283 post_methods.end());
1284 for (uint16_t id : hot_methods) {
1285 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
1286 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
1287 }
1288 for (uint16_t id : startup_methods) {
1289 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
1290 }
1291 for (uint16_t id : post_methods) {
1292 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
1293 }
1294 // Save the profile since we want to use it with dex2oat to produce an oat file.
1295 ASSERT_TRUE(info.Save(profile_file.GetFd()));
1296 // Generate a profile based odex.
1297 const std::string dir = GetScratchDir();
1298 const std::string oat_filename = dir + "/base.oat";
1299 const std::string vdex_filename = dir + "/base.vdex";
1300 std::string error_msg;
1301 const int res = GenerateOdexForTestWithStatus(
1302 {dex->GetLocation()},
1303 oat_filename,
1304 CompilerFilter::Filter::kQuicken,
1305 &error_msg,
1306 {"--profile-file=" + profile_file.GetFilename()});
1307 EXPECT_EQ(res, 0);
1308
1309 // Open our generated oat file.
1310 std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_filename.c_str(),
1311 oat_filename.c_str(),
1312 nullptr,
1313 nullptr,
1314 false,
1315 /*low_4gb*/false,
1316 dex->GetLocation().c_str(),
1317 &error_msg));
1318 ASSERT_TRUE(odex_file != nullptr);
1319 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1320 ASSERT_EQ(oat_dex_files.size(), 1u);
1321 // Check that the code sections match what we expect.
1322 for (const OatDexFile* oat_dex : oat_dex_files) {
1323 const DexLayoutSections* const sections = oat_dex->GetDexLayoutSections();
1324 // Testing of logging the sections.
1325 ASSERT_TRUE(sections != nullptr);
1326 LOG(INFO) << *sections;
1327
1328 // Load the sections into temporary variables for convenience.
1329 const DexLayoutSection& code_section =
1330 sections->sections_[static_cast<size_t>(DexLayoutSections::SectionType::kSectionTypeCode)];
1331 const DexLayoutSection::Subsection& section_hot_code =
1332 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeHot)];
1333 const DexLayoutSection::Subsection& section_sometimes_used =
1334 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeSometimesUsed)];
1335 const DexLayoutSection::Subsection& section_startup_only =
1336 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeStartupOnly)];
1337 const DexLayoutSection::Subsection& section_unused =
1338 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeUnused)];
1339
1340 // All the sections should be non-empty.
Mathieu Chartier3e0c5172017-11-12 12:58:40 -08001341 EXPECT_GT(section_hot_code.Size(), 0u);
1342 EXPECT_GT(section_sometimes_used.Size(), 0u);
1343 EXPECT_GT(section_startup_only.Size(), 0u);
1344 EXPECT_GT(section_unused.Size(), 0u);
Mathieu Chartier120aa282017-08-05 16:03:03 -07001345
1346 // Open the dex file since we need to peek at the code items to verify the layout matches what
1347 // we expect.
1348 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1349 ASSERT_TRUE(dex_file != nullptr) << error_msg;
1350 const DexFile::TypeId* type_id = dex_file->FindTypeId("LManyMethods;");
1351 ASSERT_TRUE(type_id != nullptr);
1352 dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
1353 const DexFile::ClassDef* class_def = dex_file->FindClassDef(type_idx);
1354 ASSERT_TRUE(class_def != nullptr);
1355
1356 // Count how many code items are for each category, there should be at least one per category.
1357 size_t hot_count = 0;
1358 size_t post_startup_count = 0;
1359 size_t startup_count = 0;
1360 size_t unused_count = 0;
1361 // Visit all of the methdos of the main class and cross reference the method indices to their
1362 // corresponding code item offsets to verify the layout.
1363 ClassDataItemIterator it(*dex_file, dex_file->GetClassData(*class_def));
1364 it.SkipAllFields();
Mathieu Chartierb7c273c2017-11-10 18:07:56 -08001365 for (; it.HasNextMethod(); it.Next()) {
Mathieu Chartier120aa282017-08-05 16:03:03 -07001366 const size_t method_idx = it.GetMemberIndex();
1367 const size_t code_item_offset = it.GetMethodCodeItemOffset();
1368 const bool is_hot = ContainsElement(hot_methods, method_idx);
1369 const bool is_startup = ContainsElement(startup_methods, method_idx);
1370 const bool is_post_startup = ContainsElement(post_methods, method_idx);
1371 if (is_hot) {
1372 // Hot is highest precedence, check that the hot methods are in the hot section.
Mathieu Chartier3e0c5172017-11-12 12:58:40 -08001373 EXPECT_TRUE(section_hot_code.Contains(code_item_offset));
Mathieu Chartier120aa282017-08-05 16:03:03 -07001374 ++hot_count;
1375 } else if (is_post_startup) {
1376 // Post startup is sometimes used section.
Mathieu Chartier3e0c5172017-11-12 12:58:40 -08001377 EXPECT_TRUE(section_sometimes_used.Contains(code_item_offset));
Mathieu Chartier120aa282017-08-05 16:03:03 -07001378 ++post_startup_count;
1379 } else if (is_startup) {
1380 // Startup at this point means not hot or post startup, these must be startup only then.
Mathieu Chartier3e0c5172017-11-12 12:58:40 -08001381 EXPECT_TRUE(section_startup_only.Contains(code_item_offset));
Mathieu Chartier120aa282017-08-05 16:03:03 -07001382 ++startup_count;
1383 } else {
Mathieu Chartier3e0c5172017-11-12 12:58:40 -08001384 if (section_unused.Contains(code_item_offset)) {
Alan Leung9595fd32017-10-17 17:08:19 -07001385 // If no flags are set, the method should be unused ...
1386 ++unused_count;
1387 } else {
1388 // or this method is part of the last code item and the end is 4 byte aligned.
1389 ClassDataItemIterator it2(*dex_file, dex_file->GetClassData(*class_def));
1390 it2.SkipAllFields();
Mathieu Chartierb7c273c2017-11-10 18:07:56 -08001391 for (; it2.HasNextMethod(); it2.Next()) {
Alan Leung9595fd32017-10-17 17:08:19 -07001392 EXPECT_LE(it2.GetMethodCodeItemOffset(), code_item_offset);
1393 }
1394 uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx);
1395 EXPECT_EQ((code_item_offset + code_item_size) % 4, 0u);
1396 }
Mathieu Chartier120aa282017-08-05 16:03:03 -07001397 }
1398 }
1399 DCHECK(!it.HasNext());
1400 EXPECT_GT(hot_count, 0u);
1401 EXPECT_GT(post_startup_count, 0u);
1402 EXPECT_GT(startup_count, 0u);
1403 EXPECT_GT(unused_count, 0u);
1404 }
1405}
1406
Mathieu Chartier603ccab2017-10-20 14:34:28 -07001407// Test that generating compact dex works.
1408TEST_F(Dex2oatTest, GenerateCompactDex) {
1409 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1410 // Generate a compact dex based odex.
1411 const std::string dir = GetScratchDir();
1412 const std::string oat_filename = dir + "/base.oat";
1413 const std::string vdex_filename = dir + "/base.vdex";
1414 std::string error_msg;
1415 const int res = GenerateOdexForTestWithStatus(
1416 {dex->GetLocation()},
1417 oat_filename,
1418 CompilerFilter::Filter::kQuicken,
1419 &error_msg,
1420 {"--compact-dex-level=fast"});
1421 EXPECT_EQ(res, 0);
1422 // Open our generated oat file.
1423 std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_filename.c_str(),
1424 oat_filename.c_str(),
1425 nullptr,
1426 nullptr,
1427 false,
1428 /*low_4gb*/false,
1429 dex->GetLocation().c_str(),
1430 &error_msg));
1431 ASSERT_TRUE(odex_file != nullptr);
1432 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1433 ASSERT_EQ(oat_dex_files.size(), 1u);
1434 // Check that each dex is a compact dex.
1435 for (const OatDexFile* oat_dex : oat_dex_files) {
1436 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1437 ASSERT_TRUE(dex_file != nullptr) << error_msg;
1438 ASSERT_TRUE(dex_file->IsCompactDexFile());
1439 }
1440}
1441
Andreas Gampef39208f2017-10-19 15:06:59 -07001442class Dex2oatVerifierAbort : public Dex2oatTest {};
1443
1444TEST_F(Dex2oatVerifierAbort, HardFail) {
1445 // Use VerifierDeps as it has hard-failing classes.
1446 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDeps"));
1447 std::string out_dir = GetScratchDir();
1448 const std::string base_oat_name = out_dir + "/base.oat";
1449 std::string error_msg;
1450 const int res_fail = GenerateOdexForTestWithStatus(
1451 {dex->GetLocation()},
1452 base_oat_name,
1453 CompilerFilter::Filter::kQuicken,
1454 &error_msg,
1455 {"--abort-on-hard-verifier-error"});
1456 EXPECT_NE(0, res_fail);
1457
1458 const int res_no_fail = GenerateOdexForTestWithStatus(
1459 {dex->GetLocation()},
1460 base_oat_name,
1461 CompilerFilter::Filter::kQuicken,
1462 &error_msg,
1463 {"--no-abort-on-hard-verifier-error"});
1464 EXPECT_EQ(0, res_no_fail);
1465}
1466
1467TEST_F(Dex2oatVerifierAbort, SoftFail) {
1468 // Use VerifierDepsMulti as it has hard-failing classes.
1469 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDepsMulti"));
1470 std::string out_dir = GetScratchDir();
1471 const std::string base_oat_name = out_dir + "/base.oat";
1472 std::string error_msg;
1473 const int res_fail = GenerateOdexForTestWithStatus(
1474 {dex->GetLocation()},
1475 base_oat_name,
1476 CompilerFilter::Filter::kQuicken,
1477 &error_msg,
1478 {"--abort-on-soft-verifier-error"});
1479 EXPECT_NE(0, res_fail);
1480
1481 const int res_no_fail = GenerateOdexForTestWithStatus(
1482 {dex->GetLocation()},
1483 base_oat_name,
1484 CompilerFilter::Filter::kQuicken,
1485 &error_msg,
1486 {"--no-abort-on-soft-verifier-error"});
1487 EXPECT_EQ(0, res_no_fail);
1488}
1489
Andreas Gampecac31ad2017-11-06 20:01:17 -08001490class Dex2oatDedupeCode : public Dex2oatTest {};
1491
1492TEST_F(Dex2oatDedupeCode, DedupeTest) {
1493 // Use MyClassNatives. It has lots of native methods that will produce deduplicate-able code.
1494 std::unique_ptr<const DexFile> dex(OpenTestDexFile("MyClassNatives"));
1495 std::string out_dir = GetScratchDir();
1496 const std::string base_oat_name = out_dir + "/base.oat";
1497 size_t no_dedupe_size = 0;
1498 GenerateOdexForTest(dex->GetLocation(),
1499 base_oat_name,
1500 CompilerFilter::Filter::kSpeed,
1501 { "--deduplicate-code=false" },
1502 true, // expect_success
1503 false, // use_fd
1504 [&no_dedupe_size](const OatFile& o) {
1505 no_dedupe_size = o.Size();
1506 });
1507
1508 size_t dedupe_size = 0;
1509 GenerateOdexForTest(dex->GetLocation(),
1510 base_oat_name,
1511 CompilerFilter::Filter::kSpeed,
1512 { "--deduplicate-code=true" },
1513 true, // expect_success
1514 false, // use_fd
1515 [&dedupe_size](const OatFile& o) {
1516 dedupe_size = o.Size();
1517 });
1518
1519 EXPECT_LT(dedupe_size, no_dedupe_size);
1520}
1521
Andreas Gampee1459ae2016-06-29 09:36:30 -07001522} // namespace art