Merge "runtest: Have gcstress tests skip 955-lambda-smali"
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 0f756ef..6952d69 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -20,6 +20,15 @@
ART_TARGET_SUPPORTED_ARCH := arm arm64 mips mips64 x86 x86_64
ART_HOST_SUPPORTED_ARCH := x86 x86_64
+ifneq ($(HOST_OS),darwin)
+ ART_HOST_SUPPORTED_ARCH := x86 x86_64
+else
+ # Mac OS doesn't support low-4GB allocation in a 64-bit process. So we won't be able to create
+ # our heaps.
+ ART_HOST_SUPPORTED_ARCH := x86
+ ART_MULTILIB_OVERRIDE_host := 32
+endif
+
ART_COVERAGE := false
ifeq ($(ART_COVERAGE),true)
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index a251c92..72cf978 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -127,6 +127,10 @@
LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
endif
+ ifdef ART_MULTILIB_OVERRIDE_$$(art_target_or_host)
+ art_multilib := $$(ART_MULTILIB_OVERRIDE_$$(art_target_or_host))
+ endif
+
LOCAL_MULTILIB := $$(art_multilib)
art_out_binary_name := $$(LOCAL_MODULE)
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 377cd4e..63ad9cf 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -255,6 +255,7 @@
compiler/optimizing/graph_checker_test.cc \
compiler/optimizing/graph_test.cc \
compiler/optimizing/gvn_test.cc \
+ compiler/optimizing/licm_test.cc \
compiler/optimizing/linearize_test.cc \
compiler/optimizing/liveness_test.cc \
compiler/optimizing/live_interval_test.cc \
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
new file mode 100644
index 0000000..2fc66e6
--- /dev/null
+++ b/compiler/optimizing/licm_test.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 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 "base/arena_allocator.h"
+#include "builder.h"
+#include "gtest/gtest.h"
+#include "licm.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+#include "side_effects_analysis.h"
+
+namespace art {
+
+/**
+ * Fixture class for the LICM tests.
+ */
+class LICMTest : public testing::Test {
+ public:
+ LICMTest() : pool_(), allocator_(&pool_) {
+ graph_ = CreateGraph(&allocator_);
+ }
+
+ ~LICMTest() { }
+
+ // Builds a singly-nested loop structure in CFG. Tests can further populate
+ // the basic blocks with instructions to set up interesting scenarios.
+ void BuildLoop() {
+ entry_ = new (&allocator_) HBasicBlock(graph_);
+ loop_preheader_ = new (&allocator_) HBasicBlock(graph_);
+ loop_header_ = new (&allocator_) HBasicBlock(graph_);
+ loop_body_ = new (&allocator_) HBasicBlock(graph_);
+ exit_ = new (&allocator_) HBasicBlock(graph_);
+
+ graph_->AddBlock(entry_);
+ graph_->AddBlock(loop_preheader_);
+ graph_->AddBlock(loop_header_);
+ graph_->AddBlock(loop_body_);
+ graph_->AddBlock(exit_);
+
+ graph_->SetEntryBlock(entry_);
+ graph_->SetExitBlock(exit_);
+
+ // Set up loop flow in CFG.
+ entry_->AddSuccessor(loop_preheader_);
+ loop_preheader_->AddSuccessor(loop_header_);
+ loop_header_->AddSuccessor(loop_body_);
+ loop_header_->AddSuccessor(exit_);
+ loop_body_->AddSuccessor(loop_header_);
+
+ // Provide boiler-plate instructions.
+ parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot);
+ entry_->AddInstruction(parameter_);
+ constant_ = new (&allocator_) HConstant(Primitive::kPrimInt);
+ loop_preheader_->AddInstruction(constant_);
+ loop_header_->AddInstruction(new (&allocator_) HIf(parameter_));
+ loop_body_->AddInstruction(new (&allocator_) HGoto());
+ exit_->AddInstruction(new (&allocator_) HExit());
+ }
+
+ // Performs LICM optimizations (after proper set up).
+ void PerformLICM() {
+ ASSERT_TRUE(graph_->TryBuildingSsa());
+ SideEffectsAnalysis side_effects(graph_);
+ side_effects.Run();
+ LICM licm(graph_, side_effects);
+ licm.Run();
+ }
+
+ // General building fields.
+ ArenaPool pool_;
+ ArenaAllocator allocator_;
+ HGraph* graph_;
+
+ // Specific basic blocks.
+ HBasicBlock* entry_;
+ HBasicBlock* loop_preheader_;
+ HBasicBlock* loop_header_;
+ HBasicBlock* loop_body_;
+ HBasicBlock* exit_;
+
+ HInstruction* parameter_; // "this"
+ HInstruction* constant_;
+};
+
+//
+// The actual LICM tests.
+//
+
+TEST_F(LICMTest, ConstantHoisting) {
+ BuildLoop();
+
+ // Populate the loop with instructions: set array to constant.
+ HInstruction* constant = new (&allocator_) HConstant(Primitive::kPrimDouble);
+ loop_body_->InsertInstructionBefore(constant, loop_body_->GetLastInstruction());
+ HInstruction* set_array = new (&allocator_) HArraySet(
+ parameter_, constant_, constant, Primitive::kPrimDouble, 0);
+ loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
+
+ EXPECT_EQ(constant->GetBlock(), loop_body_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+ PerformLICM();
+ EXPECT_EQ(constant->GetBlock(), loop_preheader_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+}
+
+TEST_F(LICMTest, FieldHoisting) {
+ BuildLoop();
+
+ // Populate the loop with instructions: set/get field with different types.
+ HInstruction* get_field = new (&allocator_) HInstanceFieldGet(
+ parameter_, Primitive::kPrimLong, MemberOffset(10),
+ false, kUnknownFieldIndex, graph_->GetDexFile());
+ loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
+ HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
+ parameter_, constant_, Primitive::kPrimInt, MemberOffset(20),
+ false, kUnknownFieldIndex, graph_->GetDexFile());
+ loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
+
+ EXPECT_EQ(get_field->GetBlock(), loop_body_);
+ EXPECT_EQ(set_field->GetBlock(), loop_body_);
+ PerformLICM();
+ EXPECT_EQ(get_field->GetBlock(), loop_preheader_);
+ EXPECT_EQ(set_field->GetBlock(), loop_body_);
+}
+
+TEST_F(LICMTest, NoFieldHoisting) {
+ BuildLoop();
+
+ // Populate the loop with instructions: set/get field with same types.
+ HInstruction* get_field = new (&allocator_) HInstanceFieldGet(
+ parameter_, Primitive::kPrimLong, MemberOffset(10),
+ false, kUnknownFieldIndex, graph_->GetDexFile());
+ loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction());
+ HInstruction* set_field = new (&allocator_) HInstanceFieldSet(
+ parameter_, get_field, Primitive::kPrimLong, MemberOffset(10),
+ false, kUnknownFieldIndex, graph_->GetDexFile());
+ loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction());
+
+ EXPECT_EQ(get_field->GetBlock(), loop_body_);
+ EXPECT_EQ(set_field->GetBlock(), loop_body_);
+ PerformLICM();
+ EXPECT_EQ(get_field->GetBlock(), loop_body_);
+ EXPECT_EQ(set_field->GetBlock(), loop_body_);
+}
+
+TEST_F(LICMTest, ArrayHoisting) {
+ BuildLoop();
+
+ // Populate the loop with instructions: set/get array with different types.
+ HInstruction* get_array = new (&allocator_) HArrayGet(
+ parameter_, constant_, Primitive::kPrimLong);
+ loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
+ HInstruction* set_array = new (&allocator_) HArraySet(
+ parameter_, constant_, constant_, Primitive::kPrimInt, 0);
+ loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
+
+ EXPECT_EQ(get_array->GetBlock(), loop_body_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+ PerformLICM();
+ EXPECT_EQ(get_array->GetBlock(), loop_preheader_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+}
+
+TEST_F(LICMTest, NoArrayHoisting) {
+ BuildLoop();
+
+ // Populate the loop with instructions: set/get array with same types.
+ HInstruction* get_array = new (&allocator_) HArrayGet(
+ parameter_, constant_, Primitive::kPrimLong);
+ loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction());
+ HInstruction* set_array = new (&allocator_) HArraySet(
+ parameter_, get_array, constant_, Primitive::kPrimLong, 0);
+ loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction());
+
+ EXPECT_EQ(get_array->GetBlock(), loop_body_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+ PerformLICM();
+ EXPECT_EQ(get_array->GetBlock(), loop_body_);
+ EXPECT_EQ(set_array->GetBlock(), loop_body_);
+}
+
+} // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 85aa004..f7a8486 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3607,7 +3607,7 @@
const DexFile& dex_file)
: HExpression(
field_type,
- SideEffects::SideEffects::FieldReadOfType(field_type, is_volatile)),
+ SideEffects::FieldReadOfType(field_type, is_volatile)),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) {
SetRawInputAt(0, value);
}
@@ -4058,7 +4058,7 @@
const DexFile& dex_file)
: HExpression(
field_type,
- SideEffects::SideEffects::FieldReadOfType(field_type, is_volatile)),
+ SideEffects::FieldReadOfType(field_type, is_volatile)),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) {
SetRawInputAt(0, cls);
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 710d3bc..b8ce04e 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -86,7 +86,7 @@
* Filter to apply to the visualizer. Methods whose name contain that filter will
* be dumped.
*/
-static const char* kStringFilter = "";
+static constexpr const char kStringFilter[] = "";
class PassScope;
@@ -105,12 +105,14 @@
visualizer_enabled_(!compiler_driver->GetDumpCfgFileName().empty()),
visualizer_(visualizer_output, graph, *codegen),
graph_in_bad_state_(false) {
- if (strstr(method_name, kStringFilter) == nullptr) {
- timing_logger_enabled_ = visualizer_enabled_ = false;
- }
- if (visualizer_enabled_) {
- visualizer_.PrintHeader(method_name_);
- codegen->SetDisassemblyInformation(&disasm_info_);
+ if (timing_logger_enabled_ || visualizer_enabled_) {
+ if (!IsVerboseMethod(compiler_driver, method_name)) {
+ timing_logger_enabled_ = visualizer_enabled_ = false;
+ }
+ if (visualizer_enabled_) {
+ visualizer_.PrintHeader(method_name_);
+ codegen->SetDisassemblyInformation(&disasm_info_);
+ }
}
}
@@ -169,6 +171,23 @@
}
}
+ static bool IsVerboseMethod(CompilerDriver* compiler_driver, const char* method_name) {
+ // Test an exact match to --verbose-methods. If verbose-methods is set, this overrides an
+ // empty kStringFilter matching all methods.
+ if (compiler_driver->GetCompilerOptions().HasVerboseMethods()) {
+ return compiler_driver->GetCompilerOptions().IsVerboseMethod(method_name);
+ }
+
+ // Test the kStringFilter sub-string. constexpr helper variable to silence unreachable-code
+ // warning when the string is empty.
+ constexpr bool kStringFilterEmpty = arraysize(kStringFilter) <= 1;
+ if (kStringFilterEmpty || strstr(method_name, kStringFilter) != nullptr) {
+ return true;
+ }
+
+ return false;
+ }
+
HGraph* const graph_;
const char* method_name_;
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 413b9ea..b499ddd 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -133,14 +133,27 @@
AdjustFixupIfNeeded(&fixup, ¤t_code_size, &fixups_to_recalculate);
}
while (!fixups_to_recalculate.empty()) {
- // Pop the fixup.
- FixupId fixup_id = fixups_to_recalculate.front();
- fixups_to_recalculate.pop_front();
- Fixup* fixup = GetFixup(fixup_id);
- DCHECK_NE(buffer_.Load<int16_t>(fixup->GetLocation()), 0);
- buffer_.Store<int16_t>(fixup->GetLocation(), 0);
- // See if it needs adjustment.
- AdjustFixupIfNeeded(fixup, ¤t_code_size, &fixups_to_recalculate);
+ do {
+ // Pop the fixup.
+ FixupId fixup_id = fixups_to_recalculate.front();
+ fixups_to_recalculate.pop_front();
+ Fixup* fixup = GetFixup(fixup_id);
+ DCHECK_NE(buffer_.Load<int16_t>(fixup->GetLocation()), 0);
+ buffer_.Store<int16_t>(fixup->GetLocation(), 0);
+ // See if it needs adjustment.
+ AdjustFixupIfNeeded(fixup, ¤t_code_size, &fixups_to_recalculate);
+ } while (!fixups_to_recalculate.empty());
+
+ if ((current_code_size & 2) != 0 && !literals_.empty()) {
+ // If we need to add padding before literals, this may just push some out of range,
+ // so recalculate all load literals. This makes up for the fact that we don't mark
+ // load literal as a dependency of all previous Fixups even though it actually is.
+ for (Fixup& fixup : fixups_) {
+ if (fixup.IsLoadLiteral()) {
+ AdjustFixupIfNeeded(&fixup, ¤t_code_size, &fixups_to_recalculate);
+ }
+ }
+ }
}
if (kIsDebugBuild) {
// Check that no fixup is marked as being in fixups_to_recalculate anymore.
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 838554e..41eb5d3 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -489,6 +489,10 @@
return type_;
}
+ bool IsLoadLiteral() const {
+ return GetType() >= kLoadLiteralNarrow;
+ }
+
Size GetOriginalSize() const {
return original_size_;
}
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 68b7931..004853f 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -950,4 +950,65 @@
__ GetAdjustedPosition(label.Position()));
}
+TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiBDueToAlignmentOnSecondPass) {
+ // First part: as TwoCbzBeyondMaxOffset but add one 16-bit instruction to the end,
+ // so that the size is not Aligned<4>(.). On the first pass, the assembler resizes
+ // the second CBZ because it's out of range, then it will resize the first CBZ
+ // which has been pushed out of range. Thus, after the first pass, the code size
+ // will appear Aligned<4>(.) but the final size will not be.
+ Label label0, label1, label2;
+ __ cbz(arm::R0, &label1);
+ constexpr size_t kLdrR0R0Count1 = 63;
+ for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+ __ ldr(arm::R0, arm::Address(arm::R0));
+ }
+ __ Bind(&label0);
+ __ cbz(arm::R0, &label2);
+ __ Bind(&label1);
+ constexpr size_t kLdrR0R0Count2 = 65;
+ for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+ __ ldr(arm::R0, arm::Address(arm::R0));
+ }
+ __ Bind(&label2);
+ __ ldr(arm::R0, arm::Address(arm::R0));
+
+ std::string expected_part1 =
+ "cmp r0, #0\n" // cbz r0, label1
+ "beq.n 1f\n" +
+ RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+ "0:\n"
+ "cmp r0, #0\n" // cbz r0, label2
+ "beq.n 2f\n"
+ "1:\n" +
+ RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+ "2:\n" // Here the offset is Aligned<4>(.).
+ "ldr r0, [r0]\n"; // Make the first part
+
+ // Second part: as LoadLiteralMax1KiB with the caveat that the offset of the load
+ // literal will not be Aligned<4>(.) but it will appear to be when we process the
+ // instruction during the first pass, so the literal will need a padding and it
+ // will push the literal out of range, so we shall end up with "ldr.w".
+ arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+ __ LoadLiteral(arm::R0, literal);
+ Label label;
+ __ Bind(&label);
+ constexpr size_t kLdrR0R0Count = 511;
+ for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+ __ ldr(arm::R0, arm::Address(arm::R0));
+ }
+
+ std::string expected =
+ expected_part1 +
+ "1:\n"
+ "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
+ RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+ ".align 2, 0\n"
+ "2:\n"
+ ".word 0x12345678\n";
+ DriverStr(expected, "LoadLiteralMax1KiB");
+
+ EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
+ __ GetAdjustedPosition(label.Position()));
+}
+
} // namespace art
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
index d127d35..71e9a28 100644
--- a/dalvikvm/Android.mk
+++ b/dalvikvm/Android.mk
@@ -66,16 +66,22 @@
LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
LOCAL_IS_HOST_MODULE := true
LOCAL_MULTILIB := both
+ifdef ART_MULTILIB_OVERRIDE_host
+ LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
+endif
+ifeq ($(LOCAL_MULTILIB),both)
LOCAL_MODULE_STEM_32 := dalvikvm32
LOCAL_MODULE_STEM_64 := dalvikvm64
+endif
LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
include $(BUILD_HOST_EXECUTABLE)
-
# Create symlink for the primary version target.
+ifeq ($(LOCAL_MULTILIB),both)
include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_HOST_SUFFIX)
ifdef 2ND_ART_PHONY_TEST_HOST_SUFFIX
ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
endif
+endif
+ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
index c6b4d47..a208ccf 100755
--- a/dexdump/Android.mk
+++ b/dexdump/Android.mk
@@ -50,5 +50,5 @@
LOCAL_CFLAGS += -Wall
LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
LOCAL_MODULE := dexdump2
-LOCAL_MODULE_TAGS := optional
+LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
index 988fe03..9fbd847 100755
--- a/dexlist/Android.mk
+++ b/dexlist/Android.mk
@@ -50,5 +50,5 @@
LOCAL_CFLAGS += -Wall
LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
LOCAL_MODULE := dexlist2
-LOCAL_MODULE_TAGS := optional
+LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
include $(BUILD_HOST_EXECUTABLE)
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index d133fa3..03ad2d5 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -38,6 +38,28 @@
namespace art {
+// Some tests very occasionally fail: we expect to have an unrelocated non-pic
+// odex file that is reported as needing relocation, but it is reported
+// instead as being up to date (b/22599792).
+//
+// This function adds extra checks for diagnosing why the given oat file is
+// reported up to date, when it should be non-pic needing relocation.
+// These extra diagnostics checks should be removed once b/22599792 has been
+// resolved.
+static void DiagnoseFlakyTestFailure(const OatFile& oat_file) {
+ Runtime* runtime = Runtime::Current();
+ const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ ASSERT_TRUE(image_space != nullptr);
+ const ImageHeader& image_header = image_space->GetImageHeader();
+ const OatHeader& oat_header = oat_file.GetOatHeader();
+ EXPECT_FALSE(oat_file.IsPic());
+ EXPECT_EQ(image_header.GetOatChecksum(), oat_header.GetImageFileLocationOatChecksum());
+ EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
+}
+
+
class OatFileAssistantTest : public CommonRuntimeTest {
public:
virtual void SetUp() {
@@ -186,6 +208,7 @@
// Generate an odex file for the purposes of test.
// If pic is true, generates a PIC odex.
+ // The generated odex file will be un-relocated.
void GenerateOdexForTest(const std::string& dex_location,
const std::string& odex_location,
bool pic = false) {
@@ -210,6 +233,16 @@
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
setenv("ANDROID_DATA", android_data_.c_str(), 1);
+
+ // 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, dex_location.c_str(), &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+
+ if (!pic) {
+ DiagnoseFlakyTestFailure(*odex_file);
+ }
}
void GeneratePicOdexForTest(const std::string& dex_location,
@@ -446,27 +479,6 @@
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Some tests very occasionally fail: we expect to have an unrelocated non-pic
-// odex file that is reported as needing relocation, but it is reported
-// instead as being up to date (b/22599792).
-//
-// This function adds extra checks for diagnosing why the given oat file is
-// reported up to date, when it should be non-pic needing relocation.
-// These extra diagnostics checks should be removed once b/22599792 has been
-// resolved.
-static void DiagnoseFlakyTestFailure(const OatFile& oat_file) {
- Runtime* runtime = Runtime::Current();
- const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
- ASSERT_TRUE(image_space != nullptr);
- const ImageHeader& image_header = image_space->GetImageHeader();
- const OatHeader& oat_header = oat_file.GetOatHeader();
- EXPECT_FALSE(oat_file.IsPic());
- EXPECT_EQ(image_header.GetOatChecksum(), oat_header.GetImageFileLocationOatChecksum());
- EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
- oat_header.GetImageFileLocationOatDataBegin());
- EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
-}
-
// Case: We have a DEX file and an ODEX file, but no OAT file.
// Expect: The status is kPatchOatNeeded.
TEST_F(OatFileAssistantTest, DexOdexNoOat) {
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
index ed630e3..4e516de 100755
--- a/tools/checker/checker.py
+++ b/tools/checker/checker.py
@@ -62,7 +62,7 @@
def FindCheckerFiles(path):
""" Returns a list of files to scan for check annotations in the given path.
Path to a file is returned as a single-element list, directories are
- recursively traversed and all '.java' files returned.
+ recursively traversed and all '.java' and '.smali' files returned.
"""
if not path:
Logger.fail("No source path provided")
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index 33735cb..f354395 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -76,7 +76,7 @@
if notLine is not None:
return (notLine, TestAssertion.Variant.Not, lineNo), None
- Logger.fail("Checker assertion could not be parsed", fileName, lineNo)
+ Logger.fail("Checker assertion could not be parsed: '" + line + "'", fileName, lineNo)
def __isMatchAtStart(match):
""" Tests if the given Match occurred at the beginning of the line. """