Merge "Fix dexlayout fixed point test"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 0a465c4..bcf48fd 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -40,6 +40,7 @@
Interfaces \
Lookup \
Main \
+ ManyMethods \
MethodTypes \
MultiDex \
MultiDexModifiedSecondary \
@@ -103,6 +104,7 @@
ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
+ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods
ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
ART_GTEST_image_test_DEX_DEPS := ImageLayoutA ImageLayoutB DefaultMethods
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index a0533f2..1d09a7f 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -23,7 +23,9 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
+#include "dex_file-inl.h"
#include "exec_utils.h"
+#include "jit/profile_compilation_info.h"
#include "utils.h"
namespace art {
@@ -40,9 +42,6 @@
"qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
"AAAAdQEAAAAQAAABAAAAjAEAAA==";
-static const char kDexFileLayoutInputProfile[] =
- "cHJvADAwNwAAAAAAAAgAAAB4AQMAAAAAAQ==";
-
// Dex file with catch handler unreferenced by try blocks.
// Constructed by building a dex file with try/catch blocks and hex editing.
static const char kUnreferencedCatchHandlerInputDex[] =
@@ -317,6 +316,56 @@
return true;
}
+ // Create a profile with some subset of methods and classes.
+ void CreateProfile(const std::string& input_dex,
+ const std::string& out_profile,
+ const std::string& dex_location) {
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ bool result = DexFile::Open(input_dex.c_str(),
+ input_dex,
+ false,
+ &error_msg,
+ &dex_files);
+
+ ASSERT_TRUE(result) << error_msg;
+ ASSERT_GE(dex_files.size(), 1u);
+
+ size_t profile_methods = 0;
+ size_t profile_classes = 0;
+ ProfileCompilationInfo pfi;
+ std::vector<ProfileMethodInfo> pmis;
+ std::set<DexCacheResolvedClasses> classes;
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ for (uint32_t i = 0; i < dex_file->NumMethodIds(); i += 2) {
+ if ((i & 3) != 0) {
+ pfi.AddMethodIndex(dex_location,
+ dex_file->GetLocationChecksum(),
+ i);
+ ++profile_methods;
+ }
+ }
+ DexCacheResolvedClasses cur_classes(dex_location,
+ dex_location,
+ dex_file->GetLocationChecksum());
+ // Add every even class too.
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) {
+ cur_classes.AddClass(dex_file->GetClassDef(i).class_idx_);
+ ++profile_classes;
+ }
+ }
+ pfi.AddMethodsAndClasses(pmis, classes);
+ // Write to provided file.
+ std::unique_ptr<File> file(OS::CreateEmptyFile(out_profile.c_str()));
+ ASSERT_TRUE(file != nullptr);
+ pfi.Save(file->Fd());
+ if (file->FlushCloseOrErase() != 0) {
+ PLOG(FATAL) << "Could not flush and close test file.";
+ }
+ EXPECT_GE(profile_methods, 0u);
+ EXPECT_GE(profile_classes, 0u);
+ }
+
// Runs DexFileLayout test.
bool DexFileLayoutExec(std::string* error_msg) {
ScratchFile tmp_file;
@@ -328,7 +377,8 @@
std::string dex_file = tmp_dir + "classes.dex";
WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
std::string profile_file = tmp_dir + "primary.prof";
- WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+ CreateProfile(dex_file, profile_file, dex_file);
+ // WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
std::string output_dex = tmp_dir + "classes.dex.new";
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
@@ -358,11 +408,24 @@
size_t tmp_last_slash = tmp_name.rfind("/");
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
- // Write inputs and expected outputs.
+ // Unzip the test dex file to the classes.dex destination. It is required to unzip since
+ // opening from jar recalculates the dex location checksum.
std::string dex_file = tmp_dir + "classes.dex";
- WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
+
+ std::vector<std::string> unzip_args = {
+ "/usr/bin/unzip",
+ GetTestDexFileName("ManyMethods"),
+ "classes.dex",
+ "-d",
+ tmp_dir,
+ };
+ if (!art::Exec(unzip_args, error_msg)) {
+ LOG(ERROR) << "Failed to unzip dex";
+ return false;
+ }
+
std::string profile_file = tmp_dir + "primary.prof";
- WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+ CreateProfile(dex_file, profile_file, dex_file);
std::string output_dex = tmp_dir + "classes.dex.new";
std::string second_output_dex = tmp_dir + "classes.dex.new.new";
@@ -371,14 +434,19 @@
// -v makes sure that the layout did not corrupt the dex file.
std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
+ // Recreate the profile with the new dex location. This is required so that the profile dex
+ // location matches.
+ CreateProfile(dex_file, profile_file, output_dex);
+
// -v makes sure that the layout did not corrupt the dex file.
+ // -i since the checksum won't match from the first layout.
std::vector<std::string> second_dexlayout_exec_argv =
- { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
+ { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
return false;
}
@@ -436,13 +504,11 @@
bool DexLayoutExec(ScratchFile* dex_file,
const char* dex_filename,
ScratchFile* profile_file,
- const char* profile_filename,
std::vector<std::string>& dexlayout_exec_argv) {
WriteBase64ToFile(dex_filename, dex_file->GetFile());
EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
if (profile_file != nullptr) {
- WriteBase64ToFile(profile_filename, profile_file->GetFile());
- EXPECT_EQ(profile_file->GetFile()->Flush(), 0);
+ CreateProfile(dex_file->GetFilename(), profile_file->GetFilename(), dex_file->GetFilename());
}
std::string error_msg;
const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg);
@@ -516,7 +582,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDexFileDuplicateOffset,
nullptr /* profile_file */,
- nullptr /* profile_filename */,
dexlayout_exec_argv));
}
@@ -529,7 +594,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kNullSetRefListElementInputDex,
nullptr /* profile_file */,
- nullptr /* profile_filename */,
dexlayout_exec_argv));
}
@@ -543,7 +607,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kMultiClassDataInputDex,
&temp_profile,
- kDexFileLayoutInputProfile,
dexlayout_exec_argv));
}
@@ -557,7 +620,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnalignedCodeInfoInputDex,
&temp_profile,
- kDexFileLayoutInputProfile,
dexlayout_exec_argv));
}
@@ -571,7 +633,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kClassDataBeforeCodeInputDex,
&temp_profile,
- kDexFileLayoutInputProfile,
dexlayout_exec_argv));
}
@@ -584,7 +645,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnknownTypeDebugInfoInputDex,
nullptr /* profile_file */,
- nullptr /* profile_filename */,
dexlayout_exec_argv));
}
@@ -597,7 +657,6 @@
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDuplicateCodeItemInputDex,
nullptr /* profile_file */,
- nullptr /* profile_filename */,
dexlayout_exec_argv));
}
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index a29cc6c..24dbd05 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -98,9 +98,12 @@
// Returns bin directory which contains host's prebuild tools.
static std::string GetAndroidHostToolsDir();
- // Returns bin directory wahich contains target's prebuild tools.
+ // Returns bin directory which contains target's prebuild tools.
static std::string GetAndroidTargetToolsDir(InstructionSet isa);
+ // Retuerns the filename for a test dex (i.e. XandY or ManyMethods).
+ std::string GetTestDexFileName(const char* name) const;
+
protected:
// Allow subclases such as CommonCompilerTest to add extra options.
virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
@@ -127,8 +130,6 @@
std::string GetTestAndroidRoot();
- std::string GetTestDexFileName(const char* name) const;
-
std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name);
std::unique_ptr<const DexFile> OpenTestDexFile(const char* name)
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index e903e2d..a9a5b13 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -276,6 +276,9 @@
ArenaAllocator* GetArena() { return &arena_; }
+ // Add a method index to the profile (without inline caches).
+ bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
+
private:
enum ProfileLoadSatus {
kProfileLoadWouldOverwiteData,
@@ -333,9 +336,6 @@
// already exists but has a different checksum
DexFileData* GetOrAddDexFileData(const std::string& profile_key, uint32_t checksum);
- // Add a method index to the profile (without inline caches).
- bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
-
// Add a method to the profile using its online representation (containing runtime structures).
bool AddMethod(const ProfileMethodInfo& pmi);
diff --git a/test/ManyMethods/ManyMethods.java b/test/ManyMethods/ManyMethods.java
new file mode 100644
index 0000000..b3a57f6
--- /dev/null
+++ b/test/ManyMethods/ManyMethods.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ManyMethods {
+ static class Strings {
+ public static String msg0 = "Hello World";
+ public static String msg1 = "Hello World1";
+ public static String msg2 = "Hello World2";
+ public static String msg3 = "Hello World3";
+ public static String msg4 = "Hello World4";
+ public static String msg5 = "Hello World5";
+ public static String msg6 = "Hello World6";
+ public static String msg7 = "Hello World7";
+ public static String msg8 = "Hello World8";
+ public static String msg9 = "Hello World9";
+ }
+
+ static class Printer {
+ static void Print(String s) {
+ System.out.println(s);
+ }
+ }
+
+ static class Printer2 {
+ static void Print(String s) {
+ System.out.println("AAA" + s);
+ }
+ }
+
+ public static void Print0() {
+ Printer.Print(Strings.msg0);
+ }
+
+ public static void Print1() {
+ Printer.Print(Strings.msg1);
+ }
+
+ public static void Print2() {
+ Printer.Print(Strings.msg2);
+ }
+
+ public static void Print3() {
+ Printer.Print(Strings.msg1);
+ }
+
+ public static void Print4() {
+ Printer.Print(Strings.msg2);
+ }
+
+ public static void Print5() {
+ Printer.Print(Strings.msg3);
+ }
+
+ public static void Print6() {
+ Printer2.Print(Strings.msg4);
+ }
+
+ public static void Print7() {
+ Printer.Print(Strings.msg5);
+ }
+
+ public static void Print8() {
+ Printer.Print(Strings.msg6);
+ }
+
+ public static void Print9() {
+ Printer2.Print(Strings.msg7);
+ }
+
+ public static void Print10() {
+ Printer2.Print(Strings.msg8);
+ }
+
+ public static void Print11() {
+ Printer.Print(Strings.msg9);
+ }
+
+ public static void main(String args[]) {
+ Print0();
+ Print1();
+ Print2();
+ Print3();
+ Print4();
+ Print5();
+ Print6();
+ Print7();
+ Print8();
+ Print9();
+ Print10();
+ Print11();
+ }
+}