Merge "Workaround x86 interpretter stack overflow"
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 188ddb5..75d360c 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -116,9 +116,11 @@
ART_DEFAULT_GC_TYPE ?= CMS
ART_DEFAULT_GC_TYPE_CFLAGS := -DART_DEFAULT_GC_TYPE_IS_$(ART_DEFAULT_GC_TYPE)
-LLVM_ROOT_PATH := external/llvm
-# Don't fail a dalvik minimal host build.
--include $(LLVM_ROOT_PATH)/llvm.mk
+ifeq ($(ART_USE_PORTABLE_COMPILER),true)
+ LLVM_ROOT_PATH := external/llvm
+ # Don't fail a dalvik minimal host build.
+ -include $(LLVM_ROOT_PATH)/llvm.mk
+endif
# Clang build support.
# Target builds use GCC by default.
@@ -249,7 +251,11 @@
ifeq ($(TARGET_CPU_SMP),true)
ART_TARGET_CFLAGS += -DANDROID_SMP=1
else
- ART_TARGET_CFLAGS += -DANDROID_SMP=0
+ ifeq ($(TARGET_CPU_SMP),false)
+ ART_TARGET_CFLAGS += -DANDROID_SMP=0
+ else
+ $(error TARGET_CPU_SMP must be (true|false), found $(TARGET_CPU_SMP))
+ endif
endif
ART_TARGET_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 435242a..5d74b8d 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -295,8 +295,11 @@
LoadConstantNoClobber(rs_r3, 0);
// Is lock unheld on lock or held by us (==thread_id) on unlock?
OpRegReg(kOpCmp, rs_r1, rs_r2);
- LIR* it = OpIT(kCondEq, "TEE");
- GenMemBarrier(kStoreLoad);
+
+ LIR* it = OpIT(kCondEq, "EE");
+ if (GenMemBarrier(kStoreLoad)) {
+ UpdateIT(it, "TEE");
+ }
Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
// Go expensive route - UnlockObjectFromCode(obj);
LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
@@ -356,10 +359,14 @@
(static_cast<size_t>(frame_size_) <
Thread::kStackOverflowReservedBytes));
NewLIR0(kPseudoMethodEntry);
+ bool large_frame = (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes);
if (!skip_overflow_check) {
if (Runtime::Current()->ExplicitStackOverflowChecks()) {
- /* Load stack limit */
- Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
+ if (!large_frame) {
+ /* Load stack limit */
+ LockTemp(rs_r12);
+ Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
+ }
} else {
// Implicit stack overflow check.
// Generate a load from [sp, #-overflowsize]. If this is in the stack
@@ -420,16 +427,26 @@
const bool restore_lr_;
const size_t sp_displace_;
};
- if (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes) {
+ if (large_frame) {
+ // Note: may need a temp reg, and we only have r12 free at this point.
OpRegRegImm(kOpSub, rs_rARM_LR, rs_rARM_SP, frame_size_without_spills);
+ Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_LR, rs_r12, nullptr);
// Need to restore LR since we used it as a temp.
AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, true, spill_size));
OpRegCopy(rs_rARM_SP, rs_rARM_LR); // Establish stack
} else {
- // If the frame is small enough we are guaranteed to have enough space that remains to
- // handle signals on the user stack.
+ /*
+ * If the frame is small enough we are guaranteed to have enough space that remains to
+ * handle signals on the user stack. However, we may not have any free temp
+ * registers at this point, so we'll temporarily add LR to the temp pool.
+ */
+ DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp());
+ MarkTemp(rs_rARM_LR);
+ FreeTemp(rs_rARM_LR);
OpRegRegImm(kOpSub, rs_rARM_SP, rs_rARM_SP, frame_size_without_spills);
+ Clobber(rs_rARM_LR);
+ UnmarkTemp(rs_rARM_LR);
LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_SP, rs_r12, nullptr);
AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_));
}
@@ -448,6 +465,7 @@
FreeTemp(rs_r1);
FreeTemp(rs_r2);
FreeTemp(rs_r3);
+ FreeTemp(rs_r12);
}
void ArmMir2Lir::GenExitSequence() {
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 6696cf7..1ee59c6 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -141,7 +141,7 @@
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
- void GenMemBarrier(MemBarrierKind barrier_kind);
+ bool GenMemBarrier(MemBarrierKind barrier_kind);
void GenMonitorEnter(int opt_flags, RegLocation rl_src);
void GenMonitorExit(int opt_flags, RegLocation rl_src);
void GenMoveException(RegLocation rl_dest);
@@ -160,6 +160,7 @@
LIR* OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target);
LIR* OpFpRegCopy(RegStorage r_dest, RegStorage r_src);
LIR* OpIT(ConditionCode cond, const char* guide);
+ void UpdateIT(LIR* it, const char* new_guide);
void OpEndIT(LIR* it);
LIR* OpMem(OpKind op, RegStorage r_base, int disp);
LIR* OpPcRelLoad(RegStorage reg, LIR* target);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 2e0e559..2d4834c 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -67,6 +67,34 @@
return NewLIR2(kThumb2It, code, mask);
}
+void ArmMir2Lir::UpdateIT(LIR* it, const char* new_guide) {
+ int mask;
+ int mask3 = 0;
+ int mask2 = 0;
+ int mask1 = 0;
+ ArmConditionCode code = static_cast<ArmConditionCode>(it->operands[0]);
+ int cond_bit = code & 1;
+ int alt_bit = cond_bit ^ 1;
+
+ // Note: case fallthroughs intentional
+ switch (strlen(new_guide)) {
+ case 3:
+ mask1 = (new_guide[2] == 'T') ? cond_bit : alt_bit;
+ case 2:
+ mask2 = (new_guide[1] == 'T') ? cond_bit : alt_bit;
+ case 1:
+ mask3 = (new_guide[0] == 'T') ? cond_bit : alt_bit;
+ break;
+ case 0:
+ break;
+ default:
+ LOG(FATAL) << "OAT: bad case in UpdateIT";
+ }
+ mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
+ (1 << (3 - strlen(new_guide)));
+ it->operands[1] = mask;
+}
+
void ArmMir2Lir::OpEndIT(LIR* it) {
// TODO: use the 'it' pointer to do some checks with the LIR, for example
// we could check that the number of instructions matches the mask
@@ -934,7 +962,7 @@
return OpCondBranch(c_code, target);
}
-void ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
+bool ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
#if ANDROID_SMP != 0
// Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
LIR* barrier = last_lir_insn_;
@@ -952,15 +980,21 @@
break;
}
+ bool ret = false;
+
// If the same barrier already exists, don't generate another.
if (barrier == nullptr
|| (barrier != nullptr && (barrier->opcode != kThumb2Dmb || barrier->operands[0] != dmb_flavor))) {
barrier = NewLIR1(kThumb2Dmb, dmb_flavor);
+ ret = true;
}
// At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
DCHECK(!barrier->flags.use_def_invalid);
barrier->u.m.def_mask = ENCODE_ALL;
+ return ret;
+#else
+ return false;
#endif
}
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index fe18ed9..b0211d6 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -850,7 +850,7 @@
DCHECK(!r_dest.IsPair());
load = NewLIR3(kThumb2Vldrd, r_dest.GetReg(), r_ptr.GetReg(), encoded_disp);
} else {
- load = NewLIR4(kThumb2LdrdI8, r_dest.GetLowReg(), r_dest.GetHighReg(), r_base.GetReg(),
+ load = NewLIR4(kThumb2LdrdI8, r_dest.GetLowReg(), r_dest.GetHighReg(), r_ptr.GetReg(),
encoded_disp);
}
if ((displacement & ~1020) != 0 && !r_dest.IsFloat()) {
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 51e97cd..1bcf19b 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -278,6 +278,7 @@
MarkPossibleNullPointerException(opt_flags);
LoadConstantNoClobber(rs_x3, 0);
LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_x1, rs_x2, NULL);
+ GenMemBarrier(kStoreLoad);
Store32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_x3);
LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
@@ -295,7 +296,6 @@
LIR* success_target = NewLIR0(kPseudoTargetLabel);
unlock_success_branch->target = success_target;
- GenMemBarrier(kStoreLoad);
} else {
// Explicit null-check as slow-path is entered using an IT.
GenNullCheck(rs_x0, opt_flags);
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index af0029c..418a989 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -142,7 +142,7 @@
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
- void GenMemBarrier(MemBarrierKind barrier_kind);
+ bool GenMemBarrier(MemBarrierKind barrier_kind);
void GenMonitorEnter(int opt_flags, RegLocation rl_src);
void GenMonitorExit(int opt_flags, RegLocation rl_src);
void GenMoveException(RegLocation rl_dest);
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 0465249..f2a57e7 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -712,7 +712,7 @@
return OpCondBranch(c_code, target);
}
-void Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
+bool Arm64Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
#if ANDROID_SMP != 0
// Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
LIR* barrier = last_lir_insn_;
@@ -730,15 +730,21 @@
break;
}
+ bool ret = false;
+
// If the same barrier already exists, don't generate another.
if (barrier == nullptr
|| (barrier->opcode != kA64Dmb1B || barrier->operands[0] != dmb_flavor)) {
barrier = NewLIR1(kA64Dmb1B, dmb_flavor);
+ ret = true;
}
// At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
DCHECK(!barrier->flags.use_def_invalid);
barrier->u.m.def_mask = ENCODE_ALL;
+ return ret;
+#else
+ return false;
#endif
}
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index b7ea34f..c5b40da 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -139,7 +139,7 @@
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
- void GenMemBarrier(MemBarrierKind barrier_kind);
+ bool GenMemBarrier(MemBarrierKind barrier_kind);
void GenMoveException(RegLocation rl_dest);
void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
int first_bit, int second_bit);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 2821209..35345e8 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -433,9 +433,12 @@
FreeTemp(rs_rMIPS_ARG3);
}
-void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
+bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
#if ANDROID_SMP != 0
NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
+ return true;
+#else
+ return false;
#endif
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6a0f3b2..836d2ac 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1192,8 +1192,9 @@
* barrier, then it will be used as such. Otherwise, a new LIR will be generated
* that can keep the semantics.
* @param barrier_kind The kind of memory barrier to generate.
+ * @return whether a new instruction was generated.
*/
- virtual void GenMemBarrier(MemBarrierKind barrier_kind) = 0;
+ virtual bool GenMemBarrier(MemBarrierKind barrier_kind) = 0;
virtual void GenMoveException(RegLocation rl_dest) = 0;
virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 11e7ff9..ef8c33c 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -142,7 +142,7 @@
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
- void GenMemBarrier(MemBarrierKind barrier_kind);
+ bool GenMemBarrier(MemBarrierKind barrier_kind);
void GenMoveException(RegLocation rl_dest);
void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
int first_bit, int second_bit);
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 2db9845..e3312a2 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -421,11 +421,12 @@
return false;
}
-void X86Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
+bool X86Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
#if ANDROID_SMP != 0
// Start off with using the last LIR as the barrier. If it is not enough, then we will update it.
LIR* mem_barrier = last_lir_insn_;
+ bool ret = false;
/*
* According to the JSR-133 Cookbook, for x86 only StoreLoad barriers need memory fence. All other barriers
* (LoadLoad, LoadStore, StoreStore) are nops due to the x86 memory model. For those cases, all we need
@@ -435,11 +436,13 @@
// If no LIR exists already that can be used a barrier, then generate an mfence.
if (mem_barrier == nullptr) {
mem_barrier = NewLIR0(kX86Mfence);
+ ret = true;
}
// If last instruction does not provide full barrier, then insert an mfence.
if (ProvidesFullMemoryBarrier(static_cast<X86OpCode>(mem_barrier->opcode)) == false) {
mem_barrier = NewLIR0(kX86Mfence);
+ ret = true;
}
}
@@ -451,6 +454,9 @@
DCHECK(!mem_barrier->flags.use_def_invalid);
mem_barrier->u.m.def_mask = ENCODE_ALL;
}
+ return ret;
+#else
+ return false;
#endif
}
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 72f1774..052d12e 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -270,8 +270,7 @@
runtime_linux.cc \
thread_linux.cc
-ifeq ($(HOST_ARCH),x86)
-ifneq ($(BUILD_HOST_64bit),)
+ifeq ($(HOST_ARCH),x86_64)
LIBART_HOST_SRC_FILES += \
arch/x86_64/context_x86_64.cc \
arch/x86_64/entrypoints_init_x86_64.cc \
@@ -282,6 +281,7 @@
arch/x86_64/fault_handler_x86_64.cc \
monitor_pool.cc
else
+ ifeq ($(HOST_ARCH),x86)
LIBART_HOST_SRC_FILES += \
arch/x86/context_x86.cc \
arch/x86/entrypoints_init_x86.cc \
@@ -290,10 +290,10 @@
arch/x86/quick_entrypoints_x86.S \
arch/x86/fault_handler_x86.cc \
arch/x86/thread_x86.cc
-endif
-else # HOST_ARCH != x86
+ else # HOST_ARCH != x86 && HOST_ARCH != x86_64
$(error unsupported HOST_ARCH=$(HOST_ARCH))
-endif # HOST_ARCH != x86
+ endif
+endif
LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index dc2769e..554fbbe 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -140,7 +140,8 @@
size_t LargeObjectMapSpace::Free(Thread* self, mirror::Object* ptr) {
MutexLock mu(self, lock_);
MemMaps::iterator found = mem_maps_.find(ptr);
- CHECK(found != mem_maps_.end()) << "Attempted to free large object which was not live";
+ CHECK(found != mem_maps_.end()) << "Attempted to free large object" << ptr
+ << "which was not live";
DCHECK_GE(num_bytes_allocated_, found->second->Size());
size_t allocation_size = found->second->Size();
num_bytes_allocated_ -= allocation_size;
diff --git a/test/Android.mk b/test/Android.mk
index 6e37af3..9b79abf 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -110,6 +110,7 @@
# Used outside the art project to get a list of the current tests
ART_TEST_DEX_MAKE_TARGETS := $(addprefix art-test-dex-, $(TEST_DEX_DIRECTORIES))
+ART_TEST_OAT_MAKE_TARGETS := $(addprefix oat-test-dex-, $(TEST_OAT_DIRECTORIES))
# Rules to explicitly create 2nd-arch test directories, as we use a "cp" for them
# instead of BUILD_JAVA_LIBRARY