Merge "Fix divergence between interpreter and compiler."
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c09116f..424aa7a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -65,15 +65,18 @@
$(call dexpreopt-remove-classes.dex,$@)
# Dex file dependencies for each gtest.
+ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
+
ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode
ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
ART_GTEST_dex_cache_test_DEX_DEPS := Main
ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
+ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
-ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
+ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
ART_GTEST_oat_test_DEX_DEPS := Main
ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
@@ -89,14 +92,25 @@
ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_default_no-pic_64) $(TARGET_CORE_IMAGE_default_no-pic_32)
-ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
+ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
$(HOST_CORE_IMAGE_default_no-pic_64) \
- $(HOST_CORE_IMAGE_default_no-pic_32) \
- $(HOST_OUT_EXECUTABLES)/patchoatd
-ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
+ $(HOST_CORE_IMAGE_default_no-pic_32)
+ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_default_no-pic_64) \
- $(TARGET_CORE_IMAGE_default_no-pic_32) \
- $(TARGET_OUT_EXECUTABLES)/patchoatd
+ $(TARGET_CORE_IMAGE_default_no-pic_32)
+
+ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+ $(HOST_OUT_EXECUTABLES)/patchoatd
+ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+ $(TARGET_OUT_EXECUTABLES)/patchoatd
+
+
+ART_GTEST_dex2oat_test_HOST_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_dex2oat_test_TARGET_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
# TODO: document why this is needed.
ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
@@ -157,6 +171,7 @@
cmdline/cmdline_parser_test.cc \
dexdump/dexdump_test.cc \
dexlist/dexlist_test.cc \
+ dex2oat/dex2oat_test.cc \
imgdiag/imgdiag_test.cc \
oatdump/oatdump_test.cc \
profman/profile_assistant_test.cc \
@@ -808,11 +823,15 @@
ART_GTEST_oat_file_assistant_test_DEX_DEPS :=
ART_GTEST_oat_file_assistant_test_HOST_DEPS :=
ART_GTEST_oat_file_assistant_test_TARGET_DEPS :=
+ART_GTEST_dex2oat_test_DEX_DEPS :=
+ART_GTEST_dex2oat_test_HOST_DEPS :=
+ART_GTEST_dex2oat_test_TARGET_DEPS :=
ART_GTEST_object_test_DEX_DEPS :=
ART_GTEST_proxy_test_DEX_DEPS :=
ART_GTEST_reflection_test_DEX_DEPS :=
ART_GTEST_stub_test_DEX_DEPS :=
ART_GTEST_transaction_test_DEX_DEPS :=
+ART_GTEST_dex2oat_environment_tests_DEX_DEPS :=
ART_VALGRIND_DEPENDENCIES :=
ART_VALGRIND_TARGET_DEPENDENCIES :=
$(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_TARGET_GTEST_$(dir)_DEX :=))
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 19629b1..f43f8ed 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1976,50 +1976,6 @@
__ revsh(out, in);
}
-static void GenBitCount(HInvoke* instr, bool is64bit, ArmAssembler* assembler) {
- DCHECK(instr->GetType() == Primitive::kPrimInt);
- DCHECK((is64bit && instr->InputAt(0)->GetType() == Primitive::kPrimLong) ||
- (!is64bit && instr->InputAt(0)->GetType() == Primitive::kPrimInt));
-
- LocationSummary* locations = instr->GetLocations();
- Location in = locations->InAt(0);
- Register src_0 = is64bit ? in.AsRegisterPairLow<Register>() : in.AsRegister<Register>();
- Register src_1 = is64bit ? in.AsRegisterPairHigh<Register>() : src_0;
- SRegister tmp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
- DRegister tmp_d = FromLowSToD(tmp_s);
- Register out_r = locations->Out().AsRegister<Register>();
-
- // Move data from core register(s) to temp D-reg for bit count calculation, then move back.
- // According to Cortex A57 and A72 optimization guides, compared to transferring to full D-reg,
- // transferring data from core reg to upper or lower half of vfp D-reg requires extra latency,
- // That's why for integer bit count, we use 'vmov d0, r0, r0' instead of 'vmov d0[0], r0'.
- __ vmovdrr(tmp_d, src_1, src_0); // Temp DReg |--src_1|--src_0|
- __ vcntd(tmp_d, tmp_d); // Temp DReg |c|c|c|c|c|c|c|c|
- __ vpaddld(tmp_d, tmp_d, 8, /* is_unsigned */ true); // Temp DReg |--c|--c|--c|--c|
- __ vpaddld(tmp_d, tmp_d, 16, /* is_unsigned */ true); // Temp DReg |------c|------c|
- if (is64bit) {
- __ vpaddld(tmp_d, tmp_d, 32, /* is_unsigned */ true); // Temp DReg |--------------c|
- }
- __ vmovrs(out_r, tmp_s);
-}
-
-void IntrinsicLocationsBuilderARM::VisitIntegerBitCount(HInvoke* invoke) {
- CreateIntToIntLocations(arena_, invoke);
- invoke->GetLocations()->AddTemp(Location::RequiresFpuRegister());
-}
-
-void IntrinsicCodeGeneratorARM::VisitIntegerBitCount(HInvoke* invoke) {
- GenBitCount(invoke, /* is64bit */ false, GetAssembler());
-}
-
-void IntrinsicLocationsBuilderARM::VisitLongBitCount(HInvoke* invoke) {
- VisitIntegerBitCount(invoke);
-}
-
-void IntrinsicCodeGeneratorARM::VisitLongBitCount(HInvoke* invoke) {
- GenBitCount(invoke, /* is64bit */ true, GetAssembler());
-}
-
void IntrinsicLocationsBuilderARM::VisitStringGetCharsNoCheck(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
LocationSummary::kNoCall,
@@ -2160,6 +2116,8 @@
__ Lsr(out, out, 5);
}
+UNIMPLEMENTED_INTRINSIC(ARM, IntegerBitCount)
+UNIMPLEMENTED_INTRINSIC(ARM, LongBitCount)
UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble)
UNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat)
UNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble)
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index afe0576..92b4c8e 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -344,6 +344,17 @@
}
template <typename ImmType>
+ std::string RepeatFFIb(void (Ass::*f)(FPReg, FPReg, ImmType), int imm_bits, std::string fmt) {
+ return RepeatTemplatedRegistersImmBits<FPReg, FPReg, ImmType>(f,
+ imm_bits,
+ GetFPRegisters(),
+ GetFPRegisters(),
+ &AssemblerTest::GetFPRegName,
+ &AssemblerTest::GetFPRegName,
+ fmt);
+ }
+
+ template <typename ImmType>
std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), int imm_bits, std::string fmt) {
return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f,
GetFPRegisters(),
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index c722d0c..a1d6ad6 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -647,6 +647,26 @@
DriverStr(RepeatRRIb(&mips::MipsAssembler::Movt, 3, "movt ${reg1}, ${reg2}, $fcc{imm}"), "Movt");
}
+TEST_F(AssemblerMIPSTest, MovfS) {
+ DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfS, 3, "movf.s ${reg1}, ${reg2}, $fcc{imm}"),
+ "MovfS");
+}
+
+TEST_F(AssemblerMIPSTest, MovfD) {
+ DriverStr(RepeatFFIb(&mips::MipsAssembler::MovfD, 3, "movf.d ${reg1}, ${reg2}, $fcc{imm}"),
+ "MovfD");
+}
+
+TEST_F(AssemblerMIPSTest, MovtS) {
+ DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtS, 3, "movt.s ${reg1}, ${reg2}, $fcc{imm}"),
+ "MovtS");
+}
+
+TEST_F(AssemblerMIPSTest, MovtD) {
+ DriverStr(RepeatFFIb(&mips::MipsAssembler::MovtD, 3, "movt.d ${reg1}, ${reg2}, $fcc{imm}"),
+ "MovtD");
+}
+
TEST_F(AssemblerMIPSTest, CvtSW) {
DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsw, "cvt.s.w ${reg1}, ${reg2}"), "CvtSW");
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 24a4d58..c133980 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -22,6 +22,7 @@
#include <fstream>
#include <iostream>
+#include <limits>
#include <sstream>
#include <string>
#include <unordered_set>
@@ -81,6 +82,9 @@
namespace art {
+static constexpr size_t kDefaultMinDexFilesForSwap = 2;
+static constexpr size_t kDefaultMinDexFileCumulativeSizeForSwap = 20 * MB;
+
static int original_argc;
static char** original_argv;
@@ -351,6 +355,20 @@
UsageError(" --swap-fd=<file-descriptor>: specifies a file to use for swap (by descriptor).");
UsageError(" Example: --swap-fd=10");
UsageError("");
+ UsageError(" --swap-dex-size-threshold=<size>: specifies the minimum total dex file size in");
+ UsageError(" bytes to allow the use of swap.");
+ UsageError(" Example: --swap-dex-size-threshold=1000000");
+ UsageError(" Default: %zu", kDefaultMinDexFileCumulativeSizeForSwap);
+ UsageError("");
+ UsageError(" --swap-dex-count-threshold=<count>: specifies the minimum number of dex files to");
+ UsageError(" allow the use of swap.");
+ UsageError(" Example: --swap-dex-count-threshold=10");
+ UsageError(" Default: %zu", kDefaultMinDexFilesForSwap);
+ UsageError("");
+ UsageError(" --very-large-app-threshold=<size>: specifies the minimum total dex file size in");
+ UsageError(" bytes to consider the input \"very large\" and punt on the compilation.");
+ UsageError(" Example: --very-large-app-threshold=100000000");
+ UsageError("");
UsageError(" --app-image-fd=<file-descriptor>: specify output file descriptor for app image.");
UsageError(" Example: --app-image-fd=10");
UsageError("");
@@ -473,25 +491,6 @@
pthread_t pthread_;
};
-static constexpr size_t kMinDexFilesForSwap = 2;
-static constexpr size_t kMinDexFileCumulativeSizeForSwap = 20 * MB;
-
-static bool UseSwap(bool is_image, std::vector<const DexFile*>& dex_files) {
- if (is_image) {
- // Don't use swap, we know generation should succeed, and we don't want to slow it down.
- return false;
- }
- if (dex_files.size() < kMinDexFilesForSwap) {
- // If there are less dex files than the threshold, assume it's gonna be fine.
- return false;
- }
- size_t dex_files_size = 0;
- for (const auto* dex_file : dex_files) {
- dex_files_size += dex_file->GetHeader().file_size_;
- }
- return dex_files_size >= kMinDexFileCumulativeSizeForSwap;
-}
-
class Dex2Oat FINAL {
public:
explicit Dex2Oat(TimingLogger* timings) :
@@ -1132,6 +1131,21 @@
swap_file_name_ = option.substr(strlen("--swap-file=")).data();
} else if (option.starts_with("--swap-fd=")) {
ParseUintOption(option, "--swap-fd", &swap_fd_, Usage);
+ } else if (option.starts_with("--swap-dex-size-threshold=")) {
+ ParseUintOption(option,
+ "--swap-dex-size-threshold",
+ &min_dex_file_cumulative_size_for_swap_,
+ Usage);
+ } else if (option.starts_with("--swap-dex-count-threshold=")) {
+ ParseUintOption(option,
+ "--swap-dex-count-threshold",
+ &min_dex_files_for_swap_,
+ Usage);
+ } else if (option.starts_with("--very-large-app-threshold=")) {
+ ParseUintOption(option,
+ "--very-large-app-threshold",
+ &very_large_threshold_,
+ Usage);
} else if (option.starts_with("--app-image-file=")) {
app_image_file_name_ = option.substr(strlen("--app-image-file=")).data();
} else if (option.starts_with("--app-image-fd=")) {
@@ -1414,6 +1428,19 @@
}
// Note that dex2oat won't close the swap_fd_. The compiler driver's swap space will do that.
+ // If we need to downgrade the compiler-filter for size reasons, do that check now.
+ if (!IsBootImage() && IsVeryLarge(dex_files_)) {
+ if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
+ compiler_options_->GetCompilerFilter())) {
+ LOG(INFO) << "Very large app, downgrading to verify-at-runtime.";
+ // Note: this change won't be reflected in the key-value store, as that had to be
+ // finalized before loading the dex files. This setup is currently required
+ // to get the size from the DexFile objects.
+ // TODO: refactor. b/29790079
+ compiler_options_->SetCompilerFilter(CompilerFilter::kVerifyAtRuntime);
+ }
+ }
+
if (IsBootImage()) {
// For boot image, pass opened dex files to the Runtime::Create().
// Note: Runtime acquires ownership of these dex files.
@@ -1842,10 +1869,6 @@
}
}
- CompilerOptions* GetCompilerOptions() const {
- return compiler_options_.get();
- }
-
bool IsImage() const {
return IsAppImage() || IsBootImage();
}
@@ -1897,6 +1920,30 @@
}
private:
+ bool UseSwap(bool is_image, const std::vector<const DexFile*>& dex_files) {
+ if (is_image) {
+ // Don't use swap, we know generation should succeed, and we don't want to slow it down.
+ return false;
+ }
+ if (dex_files.size() < min_dex_files_for_swap_) {
+ // If there are less dex files than the threshold, assume it's gonna be fine.
+ return false;
+ }
+ size_t dex_files_size = 0;
+ for (const auto* dex_file : dex_files) {
+ dex_files_size += dex_file->GetHeader().file_size_;
+ }
+ return dex_files_size >= min_dex_file_cumulative_size_for_swap_;
+ }
+
+ bool IsVeryLarge(std::vector<const DexFile*>& dex_files) {
+ size_t dex_files_size = 0;
+ for (const auto* dex_file : dex_files) {
+ dex_files_size += dex_file->GetHeader().file_size_;
+ }
+ return dex_files_size >= very_large_threshold_;
+ }
+
template <typename T>
static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
std::vector<T*> result;
@@ -2486,6 +2533,9 @@
bool dump_slow_timing_;
std::string swap_file_name_;
int swap_fd_;
+ size_t min_dex_files_for_swap_ = kDefaultMinDexFilesForSwap;
+ size_t min_dex_file_cumulative_size_for_swap_ = kDefaultMinDexFileCumulativeSizeForSwap;
+ size_t very_large_threshold_ = std::numeric_limits<size_t>::max();
std::string app_image_file_name_;
int app_image_fd_;
std::string profile_file_;
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
new file mode 100644
index 0000000..6188883
--- /dev/null
+++ b/dex2oat/dex2oat_test.cc
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include "common_runtime_test.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stringprintf.h"
+#include "dex2oat_environment_test.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "utils.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace art {
+
+class Dex2oatTest : public Dex2oatEnvironmentTest {
+ public:
+ virtual void TearDown() OVERRIDE {
+ Dex2oatEnvironmentTest::TearDown();
+
+ output_ = "";
+ error_msg_ = "";
+ success_ = false;
+ }
+
+ protected:
+ void GenerateOdexForTest(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter,
+ const std::vector<std::string>& extra_args = {},
+ bool expect_success = true) {
+ std::vector<std::string> args;
+ args.push_back("--dex-file=" + dex_location);
+ args.push_back("--oat-file=" + odex_location);
+ args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
+ args.push_back("--runtime-arg");
+ args.push_back("-Xnorelocate");
+
+ args.insert(args.end(), extra_args.begin(), extra_args.end());
+
+ std::string error_msg;
+ bool success = Dex2Oat(args, &error_msg);
+
+ if (expect_success) {
+ ASSERT_TRUE(success) << error_msg;
+
+ // Verify the odex file was generated as expected.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+
+ CheckFilter(filter, odex_file->GetCompilerFilter());
+ } else {
+ ASSERT_FALSE(success) << output_;
+
+ error_msg_ = error_msg;
+
+ // Verify there's no loadable odex file.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() == nullptr);
+ }
+ }
+
+ // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
+ // in subclasses when equality is not expected.
+ virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
+ EXPECT_EQ(expected, actual);
+ }
+
+ bool Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
+ Runtime* runtime = Runtime::Current();
+
+ const std::vector<gc::space::ImageSpace*>& image_spaces =
+ runtime->GetHeap()->GetBootImageSpaces();
+ if (image_spaces.empty()) {
+ *error_msg = "No image location found for Dex2Oat.";
+ return false;
+ }
+ std::string image_location = image_spaces[0]->GetImageLocation();
+
+ std::vector<std::string> argv;
+ argv.push_back(runtime->GetCompilerExecutable());
+ argv.push_back("--runtime-arg");
+ argv.push_back("-classpath");
+ argv.push_back("--runtime-arg");
+ std::string class_path = runtime->GetClassPathString();
+ if (class_path == "") {
+ class_path = OatFile::kSpecialSharedLibrary;
+ }
+ argv.push_back(class_path);
+ if (runtime->IsDebuggable()) {
+ argv.push_back("--debuggable");
+ }
+ runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
+
+ if (!runtime->IsVerificationEnabled()) {
+ argv.push_back("--compiler-filter=verify-none");
+ }
+
+ if (runtime->MustRelocateIfPossible()) {
+ argv.push_back("--runtime-arg");
+ argv.push_back("-Xrelocate");
+ } else {
+ argv.push_back("--runtime-arg");
+ argv.push_back("-Xnorelocate");
+ }
+
+ if (!kIsTargetBuild) {
+ argv.push_back("--host");
+ }
+
+ argv.push_back("--boot-image=" + image_location);
+
+ std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
+ argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
+
+ argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
+
+ // We must set --android-root.
+ const char* android_root = getenv("ANDROID_ROOT");
+ CHECK(android_root != nullptr);
+ argv.push_back("--android-root=" + std::string(android_root));
+
+ std::string command_line(Join(argv, ' '));
+
+ // We need to fix up the '&' being used for "do not check classpath."
+ size_t ampersand = command_line.find(" &");
+ CHECK_NE(ampersand, std::string::npos);
+ command_line = command_line.replace(ampersand, 2, " \\&");
+
+ command_line += " 2>&1";
+
+ // We need dex2oat to actually log things.
+ setenv("ANDROID_LOG_TAGS", "*:d", 1);
+
+ FILE* pipe = popen(command_line.c_str(), "r");
+
+ setenv("ANDROID_LOG_TAGS", "*:e", 1);
+
+ if (pipe == nullptr) {
+ success_ = false;
+ } else {
+ char buffer[128];
+
+ while (fgets(buffer, 128, pipe) != nullptr) {
+ output_ += buffer;
+ }
+
+ int result = pclose(pipe);
+ success_ = result == 0;
+ }
+ return success_;
+ }
+
+ std::string output_ = "";
+ std::string error_msg_ = "";
+ bool success_ = false;
+};
+
+class Dex2oatSwapTest : public Dex2oatTest {
+ protected:
+ void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
+ std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
+ std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
+
+ Copy(GetDexSrc1(), dex_location);
+
+ std::vector<std::string> copy(extra_args);
+
+ std::unique_ptr<ScratchFile> sf;
+ if (use_fd) {
+ sf.reset(new ScratchFile());
+ copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
+ } else {
+ std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
+ copy.push_back("--swap-file=" + swap_location);
+ }
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
+
+ CheckValidity();
+ ASSERT_TRUE(success_);
+ CheckResult(expect_use);
+ }
+
+ void CheckResult(bool expect_use) {
+ if (kIsTargetBuild) {
+ CheckTargetResult(expect_use);
+ } else {
+ CheckHostResult(expect_use);
+ }
+ }
+
+ void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
+ // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
+ // something for variants with file descriptor where we can control the lifetime of
+ // the swap file and thus take a look at it.
+ }
+
+ void CheckHostResult(bool expect_use) {
+ if (!kIsTargetBuild) {
+ if (expect_use) {
+ EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
+ << output_;
+ } else {
+ EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
+ << output_;
+ }
+ }
+ }
+
+ // Check whether the dex2oat run was really successful.
+ void CheckValidity() {
+ if (kIsTargetBuild) {
+ CheckTargetValidity();
+ } else {
+ CheckHostValidity();
+ }
+ }
+
+ void CheckTargetValidity() {
+ // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
+ // something for variants with file descriptor where we can control the lifetime of
+ // the swap file and thus take a look at it.
+ }
+
+ // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+ void CheckHostValidity() {
+ EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+ }
+};
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
+ RunTest(false /* use_fd */, false /* expect_use */);
+ RunTest(true /* use_fd */, false /* expect_use */);
+}
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
+ RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
+ RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
+}
+
+TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
+ RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
+ RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
+}
+
+TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
+ RunTest(false /* use_fd */,
+ true /* expect_use */,
+ { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
+ RunTest(true /* use_fd */,
+ true /* expect_use */,
+ { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
+}
+
+class Dex2oatVeryLargeTest : public Dex2oatTest {
+ protected:
+ void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
+ CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
+ // Ignore, we'll do our own checks.
+ }
+
+ void RunTest(CompilerFilter::Filter filter,
+ bool expect_large,
+ const std::vector<std::string>& extra_args = {}) {
+ std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+ std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+
+ Copy(GetDexSrc1(), dex_location);
+
+ std::vector<std::string> copy(extra_args);
+
+ GenerateOdexForTest(dex_location, odex_location, filter, copy);
+
+ CheckValidity();
+ ASSERT_TRUE(success_);
+ CheckResult(dex_location, odex_location, filter, expect_large);
+ }
+
+ void CheckResult(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter,
+ bool expect_large) {
+ // Host/target independent checks.
+ std::string error_msg;
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+ if (expect_large) {
+ // Note: we cannot check the following:
+ // EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
+ // odex_file->GetCompilerFilter()));
+ // The reason is that the filter override currently happens when the dex files are
+ // loaded in dex2oat, which is after the oat file has been started. Thus, the header
+ // store cannot be changed, and the original filter is set in stone.
+
+ for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
+ std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
+ ASSERT_TRUE(dex_file != nullptr);
+ uint32_t class_def_count = dex_file->NumClassDefs();
+ ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
+ for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
+ OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
+ EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
+ }
+ }
+
+ // If the input filter was "below," it should have been used.
+ if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
+ EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
+ }
+ } else {
+ EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
+ }
+
+ // Host/target dependent checks.
+ if (kIsTargetBuild) {
+ CheckTargetResult(expect_large);
+ } else {
+ CheckHostResult(expect_large);
+ }
+ }
+
+ void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
+ // TODO: Ignore for now. May do something for fd things.
+ }
+
+ void CheckHostResult(bool expect_large) {
+ if (!kIsTargetBuild) {
+ if (expect_large) {
+ EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
+ std::string::npos)
+ << output_;
+ } else {
+ EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
+ std::string::npos)
+ << output_;
+ }
+ }
+ }
+
+ // Check whether the dex2oat run was really successful.
+ void CheckValidity() {
+ if (kIsTargetBuild) {
+ CheckTargetValidity();
+ } else {
+ CheckHostValidity();
+ }
+ }
+
+ void CheckTargetValidity() {
+ // TODO: Ignore for now.
+ }
+
+ // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+ void CheckHostValidity() {
+ EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+ }
+};
+
+TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
+ RunTest(CompilerFilter::kVerifyNone, false);
+ RunTest(CompilerFilter::kVerifyAtRuntime, false);
+ RunTest(CompilerFilter::kInterpretOnly, false);
+ RunTest(CompilerFilter::kSpeed, false);
+
+ RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
+ RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
+ RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
+ RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
+}
+
+TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
+ RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
+ RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
+ RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
+ RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
+}
+
+} // namespace art
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index a95ea64..1f51311 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -384,6 +384,8 @@
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 13, "trunc.w", "fad" },
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 14, "ceil.w", "fad" },
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 15, "floor.w", "fad" },
+ { kFpMask | (0x201 << 16), kCop1 | (0x200 << 16) | 17, "movf", "fadc" },
+ { kFpMask | (0x201 << 16), kCop1 | (0x201 << 16) | 17, "movt", "fadc" },
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 26, "rint", "fad" },
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 27, "class", "fad" },
{ kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 32, "cvt.s", "fad" },
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index bd8de87..1c32024 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -73,6 +73,11 @@
level == kThreadListLock ||
// Ignore logging which may or may not have set up thread data structures.
level == kLoggingLock ||
+ // When transitioning from suspended to runnable, a daemon thread might be in
+ // a situation where the runtime is shutting down. To not crash our debug locking
+ // mechanism we just pass null Thread* to the MutexLock during that transition
+ // (see Thread::TransitionFromSuspendedToRunnable).
+ level == kThreadSuspendCountLock ||
// Avoid recursive death.
level == kAbortLock) << level;
}
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 3509d9a..741b682 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -463,7 +463,7 @@
#define ART_TARGET_NATIVETEST_DIR_STRING ""
#endif
-std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) {
+std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) const {
CHECK(name != nullptr);
std::string filename;
if (IsHost()) {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 0ce40e8..b68eb19 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -111,7 +111,7 @@
std::string GetTestAndroidRoot();
- std::string GetTestDexFileName(const char* name);
+ std::string GetTestDexFileName(const char* name) const;
std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name)
SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
new file mode 100644
index 0000000..743fbb9
--- /dev/null
+++ b/runtime/dex2oat_environment_test.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
+#define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "common_runtime_test.h"
+#include "compiler_callbacks.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "oat_file_assistant.h"
+#include "os.h"
+#include "runtime.h"
+#include "utils.h"
+
+namespace art {
+
+// Test class that provides some helpers to set a test up for compilation using dex2oat.
+class Dex2oatEnvironmentTest : public CommonRuntimeTest {
+ public:
+ virtual void SetUp() OVERRIDE {
+ CommonRuntimeTest::SetUp();
+
+ // Create a scratch directory to work from.
+ scratch_dir_ = android_data_ + "/Dex2oatEnvironmentTest";
+ ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
+
+ // Create a subdirectory in scratch for odex files.
+ odex_oat_dir_ = scratch_dir_ + "/oat";
+ ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
+
+ odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
+ ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+
+ // Verify the environment is as we expect
+ uint32_t checksum;
+ std::string error_msg;
+ ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str()))
+ << "Expected pre-compiled boot image to be at: " << GetSystemImageFile();
+ ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
+ << "Expected dex file to be at: " << GetDexSrc1();
+ ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
+ << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
+ ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
+ << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
+ ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
+ << "Expected dex file to be at: " << GetDexSrc2();
+
+ // GetMultiDexSrc2 should have the same primary dex checksum as
+ // GetMultiDexSrc1, but a different secondary dex checksum.
+ static constexpr bool kVerifyChecksum = true;
+ std::vector<std::unique_ptr<const DexFile>> multi1;
+ ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
+ GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
+ ASSERT_GT(multi1.size(), 1u);
+
+ std::vector<std::unique_ptr<const DexFile>> multi2;
+ ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
+ GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
+ ASSERT_GT(multi2.size(), 1u);
+
+ ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
+ ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
+ }
+
+ virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
+ // options->push_back(std::make_pair("-verbose:oat", nullptr));
+
+ // Set up the image location.
+ options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
+ nullptr));
+ // Make sure compilercallbacks are not set so that relocation will be
+ // enabled.
+ callbacks_.reset();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ ClearDirectory(odex_dir_.c_str());
+ ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+ ClearDirectory(odex_oat_dir_.c_str());
+ ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
+
+ ClearDirectory(scratch_dir_.c_str());
+ ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
+
+ CommonRuntimeTest::TearDown();
+ }
+
+ static void Copy(const std::string& src, const std::string& dst) {
+ std::ifstream src_stream(src, std::ios::binary);
+ std::ofstream dst_stream(dst, std::ios::binary);
+
+ dst_stream << src_stream.rdbuf();
+ }
+
+ // Returns the directory where the pre-compiled core.art can be found.
+ // TODO: We should factor out this into common tests somewhere rather than
+ // re-hardcoding it here (This was copied originally from the elf writer
+ // test).
+ std::string GetImageDirectory() const {
+ if (IsHost()) {
+ const char* host_dir = getenv("ANDROID_HOST_OUT");
+ CHECK(host_dir != nullptr);
+ return std::string(host_dir) + "/framework";
+ } else {
+ return std::string("/data/art-test");
+ }
+ }
+
+ std::string GetImageLocation() const {
+ return GetImageDirectory() + "/core.art";
+ }
+
+ std::string GetSystemImageFile() const {
+ return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
+ + "/core.art";
+ }
+
+ bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) const {
+ std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true);
+ return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
+ }
+
+ std::string GetDexSrc1() const {
+ return GetTestDexFileName("Main");
+ }
+
+ // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
+ // file stripped.
+ std::string GetStrippedDexSrc1() const {
+ return GetTestDexFileName("MainStripped");
+ }
+
+ std::string GetMultiDexSrc1() const {
+ return GetTestDexFileName("MultiDex");
+ }
+
+ // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
+ // with the contents of the secondary dex file changed.
+ std::string GetMultiDexSrc2() const {
+ return GetTestDexFileName("MultiDexModifiedSecondary");
+ }
+
+ std::string GetDexSrc2() const {
+ return GetTestDexFileName("Nested");
+ }
+
+ // Scratch directory, for dex and odex files (oat files will go in the
+ // dalvik cache).
+ const std::string& GetScratchDir() const {
+ return scratch_dir_;
+ }
+
+ // Odex directory is the subdirectory in the scratch directory where odex
+ // files should be located.
+ const std::string& GetOdexDir() const {
+ return odex_dir_;
+ }
+
+ private:
+ std::string scratch_dir_;
+ std::string odex_oat_dir_;
+ std::string odex_dir_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index e3cc77f..a1d3ed9 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "oat_file_assistant.h"
-
#include <algorithm>
#include <fstream>
#include <string>
@@ -29,8 +27,10 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "compiler_callbacks.h"
+#include "dex2oat_environment_test.h"
#include "gc/space/image_space.h"
#include "mem_map.h"
+#include "oat_file_assistant.h"
#include "oat_file_manager.h"
#include "os.h"
#include "scoped_thread_state_change.h"
@@ -39,52 +39,11 @@
namespace art {
-class OatFileAssistantTest : public CommonRuntimeTest {
+class OatFileAssistantTest : public Dex2oatEnvironmentTest {
public:
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
ReserveImageSpace();
- CommonRuntimeTest::SetUp();
-
- // Create a scratch directory to work from.
- scratch_dir_ = android_data_ + "/OatFileAssistantTest";
- ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
-
- // Create a subdirectory in scratch for odex files.
- odex_oat_dir_ = scratch_dir_ + "/oat";
- ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
-
- odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
- ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
-
- // Verify the environment is as we expect
- uint32_t checksum;
- std::string error_msg;
- ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str()))
- << "Expected pre-compiled boot image to be at: " << GetSystemImageFile();
- ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
- << "Expected dex file to be at: " << GetDexSrc1();
- ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
- << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
- ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
- << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
- ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
- << "Expected dex file to be at: " << GetDexSrc2();
-
- // GetMultiDexSrc2 should have the same primary dex checksum as
- // GetMultiDexSrc1, but a different secondary dex checksum.
- static constexpr bool kVerifyChecksum = true;
- std::vector<std::unique_ptr<const DexFile>> multi1;
- ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
- GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
- ASSERT_GT(multi1.size(), 1u);
-
- std::vector<std::unique_ptr<const DexFile>> multi2;
- ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
- GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
- ASSERT_GT(multi2.size(), 1u);
-
- ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
- ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
+ Dex2oatEnvironmentTest::SetUp();
}
// Pre-Relocate the image to a known non-zero offset so we don't have to
@@ -108,17 +67,6 @@
return Exec(argv, error_msg);
}
- virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
- // options->push_back(std::make_pair("-verbose:oat", nullptr));
-
- // Set up the image location.
- options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
- nullptr));
- // Make sure compilercallbacks are not set so that relocation will be
- // enabled.
- callbacks_.reset();
- }
-
virtual void PreRuntimeCreate() {
std::string error_msg;
ASSERT_TRUE(PreRelocateImage(&error_msg)) << error_msg;
@@ -126,94 +74,10 @@
UnreserveImageSpace();
}
- virtual void PostRuntimeCreate() {
+ virtual void PostRuntimeCreate() OVERRIDE {
ReserveImageSpace();
}
- virtual void TearDown() {
- ClearDirectory(odex_dir_.c_str());
- ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
-
- ClearDirectory(odex_oat_dir_.c_str());
- ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
-
- ClearDirectory(scratch_dir_.c_str());
- ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
-
- CommonRuntimeTest::TearDown();
- }
-
- void Copy(std::string src, std::string dst) {
- std::ifstream src_stream(src, std::ios::binary);
- std::ofstream dst_stream(dst, std::ios::binary);
-
- dst_stream << src_stream.rdbuf();
- }
-
- // Returns the directory where the pre-compiled core.art can be found.
- // TODO: We should factor out this into common tests somewhere rather than
- // re-hardcoding it here (This was copied originally from the elf writer
- // test).
- std::string GetImageDirectory() {
- if (IsHost()) {
- const char* host_dir = getenv("ANDROID_HOST_OUT");
- CHECK(host_dir != nullptr);
- return std::string(host_dir) + "/framework";
- } else {
- return std::string("/data/art-test");
- }
- }
-
- std::string GetImageLocation() {
- return GetImageDirectory() + "/core.art";
- }
-
- std::string GetSystemImageFile() {
- return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
- + "/core.art";
- }
-
- bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) {
- std::string cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA), true);
- return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
- }
-
- std::string GetDexSrc1() {
- return GetTestDexFileName("Main");
- }
-
- // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
- // file stripped.
- std::string GetStrippedDexSrc1() {
- return GetTestDexFileName("MainStripped");
- }
-
- std::string GetMultiDexSrc1() {
- return GetTestDexFileName("MultiDex");
- }
-
- // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
- // with the contents of the secondary dex file changed.
- std::string GetMultiDexSrc2() {
- return GetTestDexFileName("MultiDexModifiedSecondary");
- }
-
- std::string GetDexSrc2() {
- return GetTestDexFileName("Nested");
- }
-
- // Scratch directory, for dex and odex files (oat files will go in the
- // dalvik cache).
- std::string GetScratchDir() {
- return scratch_dir_;
- }
-
- // Odex directory is the subdirectory in the scratch directory where odex
- // files should be located.
- std::string GetOdexDir() {
- return odex_dir_;
- }
-
// Generate a non-PIC odex file for the purposes of test.
// The generated odex file will be un-relocated.
void GenerateOdexForTest(const std::string& dex_location,
@@ -334,9 +198,6 @@
image_reservation_.clear();
}
- std::string scratch_dir_;
- std::string odex_oat_dir_;
- std::string odex_dir_;
std::vector<std::unique_ptr<MemMap>> image_reservation_;
};
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index d98f82a..3fd66a7 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -201,12 +201,22 @@
<< " state=" << old_state_and_flags.as_struct.state;
} else if ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
// Wait while our suspend count is non-zero.
- MutexLock mu(this, *Locks::thread_suspend_count_lock_);
+
+ // We pass null to the MutexLock as we may be in a situation where the
+ // runtime is shutting down. Guarding ourselves from that situation
+ // requires to take the shutdown lock, which is undesirable here.
+ Thread* thread_to_pass = nullptr;
+ if (kIsDebugBuild && !IsDaemon()) {
+ // We know we can make our debug locking checks on non-daemon threads,
+ // so re-enable them on debug builds.
+ thread_to_pass = this;
+ }
+ MutexLock mu(thread_to_pass, *Locks::thread_suspend_count_lock_);
old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
// Re-check when Thread::resume_cond_ is notified.
- Thread::resume_cond_->Wait(this);
+ Thread::resume_cond_->Wait(thread_to_pass);
old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
}