Merge "Revert "Fix OOM throwing if it happens in finalizer reference""
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 386128e..e4be21b 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -122,7 +122,7 @@
endif
# Clang on the target. Target builds use GCC by default.
-ART_TARGET_CLANG :=
+ART_TARGET_CLANG := false
ART_TARGET_CLANG_arm :=
ART_TARGET_CLANG_arm64 :=
ART_TARGET_CLANG_mips :=
@@ -168,7 +168,7 @@
ART_TARGET_CLANG_CFLAGS_x86 :=
ART_TARGET_CLANG_CFLAGS_x86_64 :=
-# these are necessary for Clang ARM64 ART builds
+# These are necessary for Clang ARM64 ART builds. TODO: remove.
ART_TARGET_CLANG_CFLAGS_arm64 += \
-Wno-implicit-exception-spec-mismatch \
-DNVALGRIND \
@@ -236,6 +236,14 @@
ART_TARGET_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA)
ART_TARGET_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA)
+# Colorize clang compiler warnings.
+ifeq ($(ART_HOST_CLANG),true)
+ ART_HOST_CFLAGS += -fcolor-diagnostics
+endif
+ifeq ($(ART_TARGET_CLANG),true)
+ ART_TARGET_CFLAGS += -fcolor-diagnostics
+endif
+
ART_TARGET_LDFLAGS :=
ifeq ($(TARGET_CPU_SMP),true)
ART_TARGET_CFLAGS += -DANDROID_SMP=1
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 4279955..e411164 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -1169,8 +1169,9 @@
const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir);
uint16_t res;
if (!field_info.IsResolved() || field_info.IsVolatile()) {
- // Volatile fields always get a new memory version; field id is irrelevant.
// Unresolved fields may be volatile, so handle them as such to be safe.
+ HandleInvokeOrClInitOrAcquireOp(mir); // Volatile GETs have acquire semantics.
+ // Volatile fields always get a new memory version; field id is irrelevant.
// Use result s_reg - will be unique.
res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
} else {
@@ -1269,14 +1270,16 @@
uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
- if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
- // Class initialization can call arbitrary functions, we need to wipe aliasing values.
- HandleInvokeOrClInit(mir);
+ if (!field_info.IsResolved() || field_info.IsVolatile() ||
+ (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0)) {
+ // Volatile SGETs (and unresolved fields are potentially volatile) have acquire semantics
+ // and class initialization can call arbitrary functions, we need to wipe aliasing values.
+ HandleInvokeOrClInitOrAcquireOp(mir);
}
uint16_t res;
if (!field_info.IsResolved() || field_info.IsVolatile()) {
- // Volatile fields always get a new memory version; field id is irrelevant.
// Unresolved fields may be volatile, so handle them as such to be safe.
+ // Volatile fields always get a new memory version; field id is irrelevant.
// Use result s_reg - will be unique.
res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
} else {
@@ -1306,7 +1309,7 @@
const MirSFieldLoweringInfo& field_info = gvn_->GetMirGraph()->GetSFieldLoweringInfo(mir);
if (!field_info.IsInitialized() && (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
// Class initialization can call arbitrary functions, we need to wipe aliasing values.
- HandleInvokeOrClInit(mir);
+ HandleInvokeOrClInitOrAcquireOp(mir);
}
uint16_t type = opcode - Instruction::SPUT;
if (!field_info.IsResolved()) {
@@ -1351,7 +1354,7 @@
}
}
-void LocalValueNumbering::HandleInvokeOrClInit(MIR* mir) {
+void LocalValueNumbering::HandleInvokeOrClInitOrAcquireOp(MIR* mir) {
// Use mir->offset as modifier; without elaborate inlining, it will be unique.
global_memory_version_ =
gvn_->LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
@@ -1404,9 +1407,7 @@
case Instruction::MONITOR_ENTER:
HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
- // NOTE: Keeping all aliasing values intact. Programs that rely on loads/stores of the
- // same non-volatile locations outside and inside a synchronized block being different
- // contain races that we cannot fix.
+ HandleInvokeOrClInitOrAcquireOp(mir); // Acquire operation.
break;
case Instruction::MONITOR_EXIT:
@@ -1462,14 +1463,12 @@
// Intentional fall-through.
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_STATIC_RANGE:
- if ((mir->optimization_flags & MIR_INLINED) == 0) {
- // Make ref args aliasing.
- for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
- uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
- non_aliasing_refs_.erase(reg);
- }
- HandleInvokeOrClInit(mir);
+ // Make ref args aliasing.
+ for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
+ uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
+ non_aliasing_refs_.erase(reg);
}
+ HandleInvokeOrClInitOrAcquireOp(mir);
break;
case Instruction::MOVE_RESULT:
diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h
index e11c6e5..c60da32 100644
--- a/compiler/dex/local_value_numbering.h
+++ b/compiler/dex/local_value_numbering.h
@@ -308,7 +308,7 @@
uint16_t HandleSGet(MIR* mir, uint16_t opcode);
void HandleSPut(MIR* mir, uint16_t opcode);
void RemoveSFieldsForType(uint16_t type);
- void HandleInvokeOrClInit(MIR* mir);
+ void HandleInvokeOrClInitOrAcquireOp(MIR* mir);
bool SameMemoryVersion(const LocalValueNumbering& other) const;
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index e53c640..067bea2 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -338,16 +338,19 @@
DEF_IGET(Instruction::IGET, 1u, 0u, 0u), // Non-volatile.
DEF_IGET(Instruction::IGET, 2u, 10u, 1u), // Volatile.
DEF_IGET(Instruction::IGET, 3u, 2u, 1u), // Non-volatile.
+ DEF_IGET(Instruction::IGET, 4u, 0u, 0u), // Non-volatile.
};
PrepareIFields(ifields);
PrepareMIRs(mirs);
PerformLVN();
- ASSERT_EQ(value_names_.size(), 4u);
+ ASSERT_EQ(value_names_.size(), 5u);
EXPECT_NE(value_names_[0], value_names_[2]); // Volatile has always different value name.
EXPECT_NE(value_names_[1], value_names_[3]); // Used different base because of volatile.
+ EXPECT_NE(value_names_[1], value_names_[4]); // Not guaranteed to be the same after "acquire".
+
for (size_t i = 0; i != arraysize(mirs); ++i) {
- EXPECT_EQ((i == 2u) ? MIR_IGNORE_NULL_CHECK : 0,
+ EXPECT_EQ((i == 2u || i == 4u) ? MIR_IGNORE_NULL_CHECK : 0,
mirs_[i].optimization_flags) << i;
}
}
@@ -363,7 +366,7 @@
DEF_IGET(Instruction::IGET, 1u, 20u, 0u), // Resolved field #1, unique object.
DEF_IGET(Instruction::IGET, 2u, 21u, 0u), // Resolved field #1.
DEF_IGET_WIDE(Instruction::IGET_WIDE, 3u, 21u, 1u), // Resolved field #2.
- DEF_IGET(Instruction::IGET, 4u, 22u, 2u), // IGET doesn't clobber anything.
+ DEF_IGET(Instruction::IGET, 4u, 22u, 2u), // Unresolved IGET can be "acquire".
DEF_IGET(Instruction::IGET, 5u, 20u, 0u), // Resolved field #1, unique object.
DEF_IGET(Instruction::IGET, 6u, 21u, 0u), // Resolved field #1.
DEF_IGET_WIDE(Instruction::IGET_WIDE, 7u, 21u, 1u), // Resolved field #2.
@@ -381,14 +384,15 @@
PrepareMIRs(mirs);
PerformLVN();
ASSERT_EQ(value_names_.size(), 16u);
- EXPECT_EQ(value_names_[1], value_names_[5]);
- EXPECT_EQ(value_names_[2], value_names_[6]);
- EXPECT_EQ(value_names_[3], value_names_[7]);
- EXPECT_EQ(value_names_[1], value_names_[9]);
- EXPECT_NE(value_names_[2], value_names_[10]); // This aliased with unresolved IPUT.
- EXPECT_EQ(value_names_[3], value_names_[11]);
- EXPECT_EQ(value_names_[12], value_names_[15]);
- EXPECT_NE(value_names_[1], value_names_[14]); // This aliased with unresolved IPUT.
+ // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics.
+ EXPECT_EQ(value_names_[1], value_names_[5]); // Unique object.
+ EXPECT_NE(value_names_[2], value_names_[6]); // Not guaranteed to be the same after "acquire".
+ EXPECT_NE(value_names_[3], value_names_[7]); // Not guaranteed to be the same after "acquire".
+ EXPECT_EQ(value_names_[1], value_names_[9]); // Unique object.
+ EXPECT_NE(value_names_[6], value_names_[10]); // This aliased with unresolved IPUT.
+ EXPECT_EQ(value_names_[7], value_names_[11]); // Still the same after "release".
+ EXPECT_EQ(value_names_[12], value_names_[15]); // Still the same after "release".
+ EXPECT_NE(value_names_[1], value_names_[14]); // This aliased with unresolved IPUT.
EXPECT_EQ(mirs_[0].optimization_flags, 0u);
EXPECT_EQ(mirs_[1].optimization_flags, MIR_IGNORE_NULL_CHECK);
EXPECT_EQ(mirs_[2].optimization_flags, 0u);
@@ -409,7 +413,7 @@
static const MIRDef mirs[] = {
DEF_SGET(Instruction::SGET, 0u, 0u), // Resolved field #1.
DEF_SGET_WIDE(Instruction::SGET_WIDE, 1u, 1u), // Resolved field #2.
- DEF_SGET(Instruction::SGET, 2u, 2u), // SGET doesn't clobber anything.
+ DEF_SGET(Instruction::SGET, 2u, 2u), // Unresolved SGET can be "acquire".
DEF_SGET(Instruction::SGET, 3u, 0u), // Resolved field #1.
DEF_SGET_WIDE(Instruction::SGET_WIDE, 4u, 1u), // Resolved field #2.
DEF_SPUT(Instruction::SPUT, 5u, 2u), // SPUT clobbers field #1 (#2 is wide).
@@ -421,10 +425,11 @@
PrepareMIRs(mirs);
PerformLVN();
ASSERT_EQ(value_names_.size(), 8u);
- EXPECT_EQ(value_names_[0], value_names_[3]);
- EXPECT_EQ(value_names_[1], value_names_[4]);
- EXPECT_NE(value_names_[0], value_names_[6]); // This aliased with unresolved IPUT.
- EXPECT_EQ(value_names_[1], value_names_[7]);
+ // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics.
+ EXPECT_NE(value_names_[0], value_names_[3]); // Not guaranteed to be the same after "acquire".
+ EXPECT_NE(value_names_[1], value_names_[4]); // Not guaranteed to be the same after "acquire".
+ EXPECT_NE(value_names_[3], value_names_[6]); // This aliased with unresolved IPUT.
+ EXPECT_EQ(value_names_[4], value_names_[7]); // Still the same after "release".
for (size_t i = 0u; i != mir_count_; ++i) {
EXPECT_EQ(0, mirs_[i].optimization_flags) << i;
}
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 246ae44..51b6709 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -1163,7 +1163,7 @@
if (!MIR::DecodedInstruction::IsPseudoMirOp(mir->dalvikInsn.opcode)) {
int flags = mir->dalvikInsn.FlagsOf();
- if ((flags & Instruction::kInvoke) != 0 && (mir->optimization_flags & MIR_INLINED) == 0) {
+ if ((flags & Instruction::kInvoke) != 0) {
attributes_ &= ~METHOD_IS_LEAF;
}
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index dda9e77..bcbfb5a 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -568,8 +568,6 @@
const uint16_t* code_ptr, const uint16_t* code_end) {
bool in_try_block = try_block_addr->IsBitSet(cur_offset);
bool is_throw = (insn->dalvikInsn.opcode == Instruction::THROW);
- bool build_all_edges =
- (cu_->disable_opt & (1 << kSuppressExceptionEdges)) || is_throw || in_try_block;
/* In try block */
if (in_try_block) {
@@ -605,6 +603,8 @@
}
in_try_block = (cur_block->successor_block_list_type != kNotUsed);
}
+ bool build_all_edges =
+ (cu_->disable_opt & (1 << kSuppressExceptionEdges)) || is_throw || in_try_block;
if (!in_try_block && build_all_edges) {
BasicBlock* eh_block = CreateNewBB(kExceptionHandling);
cur_block->taken = eh_block->id;
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 2523380..0f1d765 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -566,7 +566,6 @@
break;
}
if (result) {
- invoke->optimization_flags |= MIR_INLINED;
// If the invoke has not been eliminated yet, check now whether we should do it.
// This is done so that dataflow analysis does not get tripped up seeing nop invoke.
if (static_cast<int>(invoke->dalvikInsn.opcode) != kMirOpNop) {
@@ -583,7 +582,6 @@
}
}
if (move_result != nullptr) {
- move_result->optimization_flags |= MIR_INLINED;
move_result->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
}
}
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 67a75cb..c308932 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1666,16 +1666,6 @@
}
void Mir2Lir::GenInvoke(CallInfo* info) {
- if ((info->opt_flags & MIR_INLINED) != 0) {
- // Already inlined but we may still need the null check.
- if (info->type != kStatic &&
- ((cu_->disable_opt & (1 << kNullCheckElimination)) != 0 ||
- (info->opt_flags & MIR_IGNORE_NULL_CHECK) == 0)) {
- RegLocation rl_obj = LoadValue(info->args[0], kRefReg);
- GenNullCheck(rl_obj.reg);
- }
- return;
- }
DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
->GenIntrinsic(this, info)) {
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6942c0f..e7160ad 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -500,17 +500,11 @@
break;
case Instruction::MOVE_RESULT_WIDE:
- if ((opt_flags & MIR_INLINED) != 0) {
- break; // Nop - combined w/ previous invoke.
- }
StoreValueWide(rl_dest, GetReturnWide(LocToRegClass(rl_dest)));
break;
case Instruction::MOVE_RESULT:
case Instruction::MOVE_RESULT_OBJECT:
- if ((opt_flags & MIR_INLINED) != 0) {
- break; // Nop - combined w/ previous invoke.
- }
StoreValue(rl_dest, GetReturn(LocToRegClass(rl_dest)));
break;
@@ -867,7 +861,7 @@
case Instruction::INVOKE_STATIC_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, true));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
// If the invocation is not inlined, we can assume there is already a
// suspend check at the return site
mir_graph_->AppendGenSuspendTestList(bb);
@@ -875,59 +869,59 @@
break;
case Instruction::INVOKE_STATIC:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kStatic, false));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_DIRECT:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, false));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_DIRECT_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_VIRTUAL:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_SUPER:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, false));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_SUPER_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kSuper, true));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_INTERFACE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, false));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
case Instruction::INVOKE_INTERFACE_RANGE:
GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kInterface, true));
- if (!kLeafOptimization && (opt_flags & MIR_INLINED) == 0) {
+ if (!kLeafOptimization) {
mir_graph_->AppendGenSuspendTestList(bb);
}
break;
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 30384ec..6898b50 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -1113,20 +1113,18 @@
}
uint32_t index = mir->dalvikInsn.vB;
- if (!(mir->optimization_flags & MIR_INLINED)) {
- DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
- DexFileMethodInliner* method_inliner =
- cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
- InlineMethod method;
- if (method_inliner->IsIntrinsic(index, &method)) {
- switch (method.opcode) {
- case kIntrinsicAbsDouble:
- case kIntrinsicMinMaxDouble:
- store_method_addr_ = true;
- break;
- default:
- break;
- }
+ DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
+ DexFileMethodInliner* method_inliner =
+ cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file);
+ InlineMethod method;
+ if (method_inliner->IsIntrinsic(index, &method)) {
+ switch (method.opcode) {
+ case kIntrinsicAbsDouble:
+ case kIntrinsicMinMaxDouble:
+ store_method_addr_ = true;
+ break;
+ default:
+ break;
}
}
}
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 1dcd4b3..f432e66 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1991,7 +1991,7 @@
MemberOffset offs) {
X86_64ManagedRegister dest = mdest.AsX86_64();
CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
- movq(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs));
+ movl(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs));
if (kPoisonHeapReferences) {
negl(dest.AsCpuRegister());
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2cf3820..6ed27bb 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1179,7 +1179,7 @@
uint32_t image_oat_checksum = 0;
uintptr_t image_oat_data_begin = 0;
int32_t image_patch_delta = 0;
- if (instruction_set == Runtime::Current()->GetInstructionSet()) {
+ if (instruction_set == runtime->GetInstructionSet()) {
const ImageHeader& image_header = image_space->GetImageHeader();
image_oat_checksum = image_header.GetOatChecksum();
image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 353d00c..59630fe 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -149,7 +149,8 @@
arg_vector.push_back(oat_file_option_string);
Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
- CHECK_EQ(image_isa, kRuntimeISA) << "We should always be generating an image for the current isa.";
+ CHECK_EQ(image_isa, kRuntimeISA)
+ << "We should always be generating an image for the current isa.";
int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
ART_BASE_ADDRESS_MAX_DELTA);
@@ -270,10 +271,10 @@
return Exec(argv, error_msg);
}
-static ImageHeader* ReadSpecificImageHeaderOrDie(const char* filename) {
+static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
std::unique_ptr<ImageHeader> hdr(new ImageHeader);
if (!ReadSpecificImageHeader(filename, hdr.get())) {
- LOG(FATAL) << "Unable to read image header for " << filename;
+ *error_msg = StringPrintf("Unable to read image header for %s", filename);
return nullptr;
}
return hdr.release();
@@ -281,6 +282,17 @@
ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
const InstructionSet image_isa) {
+ std::string error_msg;
+ ImageHeader* image_header = ReadImageHeader(image_location, image_isa, &error_msg);
+ if (image_header == nullptr) {
+ LOG(FATAL) << error_msg;
+ }
+ return image_header;
+}
+
+ImageHeader* ImageSpace::ReadImageHeader(const char* image_location,
+ const InstructionSet image_isa,
+ std::string* error_msg) {
std::string system_filename;
bool has_system = false;
std::string cache_filename;
@@ -294,33 +306,37 @@
std::unique_ptr<ImageHeader> sys_hdr(new ImageHeader);
std::unique_ptr<ImageHeader> cache_hdr(new ImageHeader);
if (!ReadSpecificImageHeader(system_filename.c_str(), sys_hdr.get())) {
- LOG(FATAL) << "Unable to read image header for " << image_location << " at "
- << system_filename;
+ *error_msg = StringPrintf("Unable to read image header for %s at %s",
+ image_location, system_filename.c_str());
return nullptr;
}
if (!ReadSpecificImageHeader(cache_filename.c_str(), cache_hdr.get())) {
- LOG(FATAL) << "Unable to read image header for " << image_location << " at "
- << cache_filename;
+ *error_msg = StringPrintf("Unable to read image header for %s at %s",
+ image_location, cache_filename.c_str());
return nullptr;
}
if (sys_hdr->GetOatChecksum() != cache_hdr->GetOatChecksum()) {
- LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
+ *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+ image_location);
return nullptr;
}
return cache_hdr.release();
} else if (!has_cache) {
- LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
+ *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+ image_location);
return nullptr;
} else if (!has_system && has_cache) {
// This can probably just use the cache one.
- return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
}
} else {
// We don't want to relocate, Just pick the appropriate one if we have it and return.
if (has_system && has_cache) {
// We want the cache if the checksum matches, otherwise the system.
- std::unique_ptr<ImageHeader> system(ReadSpecificImageHeaderOrDie(system_filename.c_str()));
- std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeaderOrDie(cache_filename.c_str()));
+ std::unique_ptr<ImageHeader> system(ReadSpecificImageHeader(system_filename.c_str(),
+ error_msg));
+ std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeader(cache_filename.c_str(),
+ error_msg));
if (system.get() == nullptr ||
(cache.get() != nullptr && cache->GetOatChecksum() == system->GetOatChecksum())) {
return cache.release();
@@ -328,14 +344,14 @@
return system.release();
}
} else if (has_system) {
- return ReadSpecificImageHeaderOrDie(system_filename.c_str());
+ return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
} else if (has_cache) {
- return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
}
}
}
- LOG(FATAL) << "Unable to find image file for: " << image_location;
+ *error_msg = StringPrintf("Unable to find image file for %s", image_location);
return nullptr;
}
@@ -563,12 +579,13 @@
CHECK_EQ(image_header.GetImageBegin(), map->Begin());
DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
- std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
- PROT_READ, MAP_PRIVATE,
- file->Fd(), image_header.GetBitmapOffset(),
- false,
- image_filename,
- error_msg));
+ std::unique_ptr<MemMap> image_map(
+ MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
+ PROT_READ, MAP_PRIVATE,
+ file->Fd(), image_header.GetBitmapOffset(),
+ false,
+ image_filename,
+ error_msg));
if (image_map.get() == nullptr) {
*error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
return nullptr;
@@ -616,11 +633,14 @@
runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+ Runtime::kSaveAll);
callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+ Runtime::kRefsOnly);
callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+ Runtime::kRefsAndArgs);
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 2586ece..d7f8057 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -47,10 +47,17 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Reads the image header from the specified image location for the
- // instruction set image_isa.
+ // instruction set image_isa or dies trying.
static ImageHeader* ReadImageHeaderOrDie(const char* image_location,
InstructionSet image_isa);
+ // Reads the image header from the specified image location for the
+ // instruction set image_isa. Returns nullptr on failure, with
+ // reason in error_msg.
+ static ImageHeader* ReadImageHeader(const char* image_location,
+ InstructionSet image_isa,
+ std::string* error_msg);
+
// Give access to the OatFile.
const OatFile* GetOatFile() const;
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 64d4fe2..23f46f4 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -16,6 +16,7 @@
#include <limits.h>
+#include "ScopedUtfChars.h"
#include "class_linker-inl.h"
#include "common_throws.h"
#include "debugger.h"
@@ -24,6 +25,8 @@
#include "gc/allocator/dlmalloc.h"
#include "gc/heap.h"
#include "gc/space/dlmalloc_space.h"
+#include "gc/space/image_space.h"
+#include "instruction_set.h"
#include "intern_table.h"
#include "jni_internal.h"
#include "mirror/art_method-inl.h"
@@ -91,7 +94,8 @@
return nullptr;
}
Runtime* runtime = Runtime::Current();
- mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
+ mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
+ &element_class);
if (UNLIKELY(array_class == nullptr)) {
return nullptr;
}
@@ -518,6 +522,28 @@
env->ReleaseStringUTFChars(pkgName, pkgNameChars);
}
+static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
+ ScopedUtfChars instruction_set(env, java_instruction_set);
+ if (instruction_set.c_str() == nullptr) {
+ return JNI_FALSE;
+ }
+ InstructionSet isa = GetInstructionSetFromString(instruction_set.c_str());
+ if (isa == kNone) {
+ ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException"));
+ std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str()));
+ env->ThrowNew(iae.get(), message.c_str());
+ return JNI_FALSE;
+ }
+ std::string error_msg;
+ std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeader(
+ Runtime::Current()->GetImageLocation().c_str(), isa, &error_msg));
+ return image_header.get() != nullptr;
+}
+
+static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) {
+ return env->NewStringUTF(GetInstructionSetString(kRuntimeISA));
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -543,7 +569,10 @@
NATIVE_METHOD(VMRuntime, is64Bit, "!()Z"),
NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "!()Z"),
NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
- NATIVE_METHOD(VMRuntime, registerAppInfo, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMRuntime, registerAppInfo,
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
+ NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
};
void register_dalvik_system_VMRuntime(JNIEnv* env) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 49f8c63..48439b6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -678,6 +678,7 @@
compiler_executable_ = options->compiler_executable_;
compiler_options_ = options->compiler_options_;
image_compiler_options_ = options->image_compiler_options_;
+ image_location_ = options->image_;
max_spins_before_thin_lock_inflation_ = options->max_spins_before_thin_lock_inflation_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 35e3a88..1a6c6e0 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -137,6 +137,10 @@
return image_compiler_options_;
}
+ const std::string& GetImageLocation() const {
+ return image_location_;
+ }
+
const ProfilerOptions& GetProfilerOptions() const {
return profiler_options_;
}
@@ -537,6 +541,7 @@
std::string patchoat_executable_;
std::vector<std::string> compiler_options_;
std::vector<std::string> image_compiler_options_;
+ std::string image_location_;
std::string boot_class_path_string_;
std::string class_path_string_;
diff --git a/test/115-native-bridge/src/NativeBridgeMain.java b/test/115-native-bridge/src/NativeBridgeMain.java
index a531f92..2405627 100644
--- a/test/115-native-bridge/src/NativeBridgeMain.java
+++ b/test/115-native-bridge/src/NativeBridgeMain.java
@@ -15,6 +15,7 @@
*/
import java.lang.reflect.Method;
+import java.lang.System;
// This is named Main as it is a copy of JniTest, so that we can re-use the native implementations
// from libarttest.
@@ -29,6 +30,7 @@
testShortMethod();
testBooleanMethod();
testCharMethod();
+ testEnvironment();
}
public static native void testFindClassOnAttachedNativeThread();
@@ -147,6 +149,24 @@
}
}
}
+
+ private static void testEnvironment() {
+ String osArch = System.getProperty("os.arch");
+ if (!"os.arch".equals(osArch)) {
+ throw new AssertionError("unexpected value for os.arch: " + osArch);
+ }
+ // TODO: improve the build script to get these running as well.
+ // if (!"cpu_abi".equals(Build.CPU_ABI)) {
+ // throw new AssertionError("unexpected value for cpu_abi");
+ // }
+ // if (!"cpu_abi2".equals(Build.CPU_ABI2)) {
+ // throw new AssertionError("unexpected value for cpu_abi2");
+ // }
+ // String[] expectedSupportedAbis = {"supported1", "supported2", "supported3"};
+ // if (Arrays.equals(expectedSupportedAbis, Build.SUPPORTED_ABIS)) {
+ // throw new AssertionError("unexpected value for supported_abis");
+ // }
+ }
}
public class NativeBridgeMain {
diff --git a/test/118-noimage-dex2oat/expected.txt b/test/118-noimage-dex2oat/expected.txt
index 472a5f2..6825fae 100644
--- a/test/118-noimage-dex2oat/expected.txt
+++ b/test/118-noimage-dex2oat/expected.txt
@@ -1,6 +1,6 @@
Run -Xnoimage-dex2oat
-Has image is false, is image dex2oat enabled is false.
+Has image is false, is image dex2oat enabled is false, is BOOTCLASSPATH on disk is false.
Run -Ximage-dex2oat
-Has image is true, is image dex2oat enabled is true.
+Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
Run default
-Has image is true, is image dex2oat enabled is true.
+Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
diff --git a/test/118-noimage-dex2oat/src/Main.java b/test/118-noimage-dex2oat/src/Main.java
index 11c736a..c83b84d 100644
--- a/test/118-noimage-dex2oat/src/Main.java
+++ b/test/118-noimage-dex2oat/src/Main.java
@@ -14,18 +14,28 @@
* limitations under the License.
*/
+import java.lang.reflect.Method;
+
public class Main {
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
boolean hasImage = hasImage();
+ String instructionSet = VMRuntime.getCurrentInstructionSet();
+ boolean isBootClassPathOnDisk = VMRuntime.isBootClassPathOnDisk(instructionSet);
System.out.println(
"Has image is " + hasImage + ", is image dex2oat enabled is "
- + isImageDex2OatEnabled() + ".");
+ + isImageDex2OatEnabled() + ", is BOOTCLASSPATH on disk is "
+ + isBootClassPathOnDisk + ".");
if (hasImage && !isImageDex2OatEnabled()) {
throw new Error("Image with dex2oat disabled runs with an oat file");
} else if (!hasImage && isImageDex2OatEnabled()) {
throw new Error("Image with dex2oat enabled runs without an oat file");
}
+ if (hasImage && !isBootClassPathOnDisk) {
+ throw new Error("Image with dex2oat disabled runs with an image file");
+ } else if (!hasImage && isBootClassPathOnDisk) {
+ throw new Error("Image with dex2oat enabled runs without an image file");
+ }
}
static {
@@ -35,4 +45,26 @@
private native static boolean hasImage();
private native static boolean isImageDex2OatEnabled();
+
+ private static class VMRuntime {
+ private static final Method getCurrentInstructionSetMethod;
+ private static final Method isBootClassPathOnDiskMethod;
+ static {
+ try {
+ Class c = Class.forName("dalvik.system.VMRuntime");
+ getCurrentInstructionSetMethod = c.getDeclaredMethod("getCurrentInstructionSet");
+ isBootClassPathOnDiskMethod = c.getDeclaredMethod("isBootClassPathOnDisk",
+ String.class);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String getCurrentInstructionSet() throws Exception {
+ return (String) getCurrentInstructionSetMethod.invoke(null);
+ }
+ public static boolean isBootClassPathOnDisk(String instructionSet) throws Exception {
+ return (boolean) isBootClassPathOnDiskMethod.invoke(null, instructionSet);
+ }
+ }
}
diff --git a/test/123-compiler-regressions-mt/expected.txt b/test/123-compiler-regressions-mt/expected.txt
new file mode 100644
index 0000000..a11e5bf
--- /dev/null
+++ b/test/123-compiler-regressions-mt/expected.txt
@@ -0,0 +1,2 @@
+b17689750TestVolatile passed.
+b17689750TestMonitor passed.
diff --git a/test/123-compiler-regressions-mt/info.txt b/test/123-compiler-regressions-mt/info.txt
new file mode 100644
index 0000000..cac7e75
--- /dev/null
+++ b/test/123-compiler-regressions-mt/info.txt
@@ -0,0 +1,6 @@
+This is a test for bad optimizations affecting multi-threaded program
+behavior.
+
+This test covers fixed AOT/JIT bugs to prevent regressions.
+
+17689750 GVN assigns the same value names across MONITOR_ENTER and volatile reads.
diff --git a/test/123-compiler-regressions-mt/src/Main.java b/test/123-compiler-regressions-mt/src/Main.java
new file mode 100644
index 0000000..11fa021
--- /dev/null
+++ b/test/123-compiler-regressions-mt/src/Main.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Test for Jit regressions.
+ */
+public class Main {
+ public static void main(String args[]) throws Exception {
+ b17689750TestVolatile();
+ b17689750TestMonitor();
+ }
+
+ static void b17689750TestVolatile() {
+ final B17689750TestVolatile test = new B17689750TestVolatile();
+ new Thread() {
+ public void run() {
+ test.thread1();
+ }
+ }.start();
+ try {
+ test.thread2();
+ } catch (NullPointerException expected) {
+ System.out.println("b17689750TestVolatile passed.");
+ }
+ }
+
+ static void b17689750TestMonitor() {
+ final B17689750TestMonitor test = new B17689750TestMonitor();
+ new Thread() {
+ public void run() {
+ test.thread1();
+ }
+ }.start();
+ try {
+ test.thread2();
+ } catch (NullPointerException expected) {
+ System.out.println("b17689750TestMonitor passed.");
+ }
+ }
+}
+
+class B17689750TestVolatile {
+ private volatile int state = 0;
+ private int[] values = { 42 };
+
+ void thread1() {
+ while (state != 1) { } // Busy loop.
+ values = null;
+ state = 2;
+ }
+
+ void thread2() {
+ int[] vs1 = values;
+ state = 1;
+ while (state != 2) { } // Busy loop.
+ int[] vs2 = values;
+ int v1 = vs1[0];
+ int v2 = vs2[0];
+ System.out.println("b17689750TestVolatile failed: " + v1 + ", " + v2);
+ }
+}
+
+class B17689750TestMonitor {
+ private int state = 0;
+ private Object lock = new Object();
+ private int[] values = { 42 };
+
+ void thread1() {
+ int s;
+ do {
+ synchronized (lock) {
+ s = state;
+ }
+ } while (s != 1); // Busy loop.
+
+ synchronized (lock) {
+ values = null;
+ state = 2;
+ }
+ }
+
+ void thread2() {
+ int[] vs1;
+ synchronized (lock) {
+ vs1 = values;
+ state = 1;
+ }
+
+ int s;
+ do {
+ synchronized (lock) {
+ s = state;
+ }
+ } while (s != 2); // Busy loop.
+
+ int[] vs2 = values;
+ int v1 = vs1[0];
+ int v2 = vs2[0];
+ System.out.println("b17689750TestMonitor failed: " + v1 + ", " + v2);
+ }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 302db38..ae5b08f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -526,7 +526,7 @@
$(call define-test-art-run-test-group,test-art-$(target)-run-test-$(test),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(test))_RULES)))))
$(foreach target, $(TARGET_TYPES), \
$(foreach address_size, $(ADDRESS_SIZES_$(call name-to-var,$(target))), $(eval \
- $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(address_size),$(ART_RUN_TEST_$(address_size)_RULES)))))
+ $(call define-test-art-run-test-group,test-art-$(target)-run-test$(address_size),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(address_size)_RULES)))))
# Clear variables now we're finished with them.
$(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))