Merge "ART: Implicit checks in the compiler are independent from Runtime"
diff --git a/Android.mk b/Android.mk
index f7f65ac..593ee04 100644
--- a/Android.mk
+++ b/Android.mk
@@ -189,6 +189,13 @@
test-art-host-oat: test-art-host-oat-default test-art-host-oat-interpreter
@echo test-art-host-oat PASSED
+FAILING_OPTIMIZING_MESSAGE := failed with the optimizing compiler. If the test passes \
+ with Quick and interpreter, it is probably just a bug in the optimizing compiler. Please \
+ add the test name to the FAILING_OPTIMIZING_TESTS Makefile variable in art/Android.mk, \
+ and file a bug.
+
+# Placeholder for failing tests on the optimizing compiler.
+
define declare-test-art-host-run-test
.PHONY: test-art-host-run-test-default-$(1)
test-art-host-run-test-default-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
@@ -197,6 +204,14 @@
TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS += test-art-host-run-test-default-$(1)
+.PHONY: test-art-host-run-test-optimizing-$(1)
+test-art-host-run-test-optimizing-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+ DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test -Xcompiler-option --compiler-backend=Optimizing $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host $(1) \
+ || (echo -e "\x1b[31;01mTest $(1) $(FAILING_OPTIMIZING_MESSAGE)\x1b[0m" && exit 1)
+ @echo test-art-host-run-test-optimizing-$(1) PASSED
+
+TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS += test-art-host-run-test-optimizing-$(1)
+
.PHONY: test-art-host-run-test-interpreter-$(1)
test-art-host-run-test-interpreter-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host --interpreter $(1)
@@ -205,7 +220,7 @@
TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS += test-art-host-run-test-interpreter-$(1)
.PHONY: test-art-host-run-test-$(1)
-test-art-host-run-test-$(1): test-art-host-run-test-default-$(1) test-art-host-run-test-interpreter-$(1)
+test-art-host-run-test-$(1): test-art-host-run-test-default-$(1) test-art-host-run-test-interpreter-$(1) test-art-host-run-test-optimizing-$(1)
endef
@@ -215,12 +230,21 @@
test-art-host-run-test-default: $(TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS)
@echo test-art-host-run-test-default PASSED
+FAILING_OPTIMIZING_TESTS :=
+$(foreach test, $(FAILING_OPTIMIZING_TESTS), \
+ $(eval TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS := $(filter-out test-art-host-run-test-optimizing-$(test), $(TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS))))
+
+.PHONY: test-art-host-run-test-optimizing
+test-art-host-run-test-optimizing: $(TEST_ART_HOST_RUN_TEST_OPTIMIZING_TARGETS)
+ $(foreach test, $(FAILING_OPTIMIZING_TESTS), $(info Optimizing compiler has skipped $(test)))
+ @echo test-art-host-run-test-optimizing PASSED
+
.PHONY: test-art-host-run-test-interpreter
test-art-host-run-test-interpreter: $(TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS)
@echo test-art-host-run-test-interpreter PASSED
.PHONY: test-art-host-run-test
-test-art-host-run-test: test-art-host-run-test-default test-art-host-run-test-interpreter
+test-art-host-run-test: test-art-host-run-test-default test-art-host-run-test-interpreter test-art-host-run-test-optimizing
@echo test-art-host-run-test PASSED
########################################################################
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index dae6a4f..590c767 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -356,11 +356,11 @@
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
- (static_cast<size_t>(frame_size_) <
- Thread::kStackOverflowReservedBytes));
+ bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !IsLargeFrame(frame_size_, kArm);
NewLIR0(kPseudoMethodEntry);
- bool large_frame = (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes);
+ constexpr size_t kStackOverflowReservedUsableBytes = kArmStackOverflowReservedBytes -
+ Thread::kStackOverflowSignalReservedBytes;
+ bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes);
if (!skip_overflow_check) {
if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
if (!large_frame) {
@@ -381,7 +381,7 @@
// This is done before the callee save instructions to avoid any possibility
// of these overflowing. This uses r12 and that's never saved in a callee
// save.
- OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, Thread::kStackOverflowReservedBytes);
+ OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, kArmStackOverflowReservedBytes);
Load32Disp(rs_r12, 0, rs_r12);
MarkPossibleStackOverflowException();
}
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index c1ce03d..3a6012e 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -219,7 +219,8 @@
kA64First = 0,
kA64Adc3rrr = kA64First, // adc [00011010000] rm[20-16] [000000] rn[9-5] rd[4-0].
kA64Add4RRdT, // add [s001000100] imm_12[21-10] rn[9-5] rd[4-0].
- kA64Add4rrro, // add [00001011000] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
+ kA64Add4rrro, // add [00001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
+ kA64Add4rrre, // add [00001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
kA64Adr2xd, // adr [0] immlo[30-29] [10000] immhi[23-5] rd[4-0].
kA64And3Rrl, // and [00010010] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
kA64And4rrro, // and [00001010] shift[23-22] [N=0] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
@@ -328,7 +329,8 @@
kA64Stxr3wrX, // stxr[11001000000] rs[20-16] [011111] rn[9-5] rt[4-0].
kA64Stlxr3wrX, // stlxr[11001000000] rs[20-16] [111111] rn[9-5] rt[4-0].
kA64Sub4RRdT, // sub [s101000100] imm_12[21-10] rn[9-5] rd[4-0].
- kA64Sub4rrro, // sub [s1001011000] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
+ kA64Sub4rrro, // sub [s1001011000] rm[20-16] imm_6[15-10] rn[9-5] rd[4-0].
+ kA64Sub4rrre, // sub [s1001011001] rm[20-16] option[15-13] imm_3[12-10] rn[9-5] rd[4-0].
kA64Subs3rRd, // subs[s111000100] imm_12[21-10] rn[9-5] rd[4-0].
kA64Tst3rro, // tst alias of "ands rzr, arg1, arg2, arg3".
kA64Ubfm4rrdd, // ubfm[s10100110] N[22] imm_r[21-16] imm_s[15-10] rn[9-5] rd[4-0].
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index c5bd005..fe3bd6a 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -115,6 +115,10 @@
kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE1,
"add", "!0r, !1r, !2r!3o", kFixupNone),
+ ENCODING_MAP(WIDE(kA64Add4rrre), SF_VARIANTS(0x0b200000),
+ kFmtRegROrSp, 4, 0, kFmtRegROrSp, 9, 5, kFmtRegR, 20, 16,
+ kFmtExtend, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+ "add", "!0r, !1r, !2r!3o", kFixupNone),
// Note: adr is binary, but declared as tertiary. The third argument is used while doing the
// fixups and contains information to identify the adr label.
ENCODING_MAP(kA64Adr2xd, NO_VARIANTS(0x10000000),
@@ -558,6 +562,10 @@
kFmtRegR, 4, 0, kFmtRegR, 9, 5, kFmtRegR, 20, 16,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
"sub", "!0r, !1r, !2r!3o", kFixupNone),
+ ENCODING_MAP(WIDE(kA64Sub4rrre), SF_VARIANTS(0x4b200000),
+ kFmtRegROrSp, 4, 0, kFmtRegROrSp, 9, 5, kFmtRegR, 20, 16,
+ kFmtExtend, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
+ "sub", "!0r, !1r, !2r!3o", kFixupNone),
ENCODING_MAP(WIDE(kA64Subs3rRd), SF_VARIANTS(0x71000000),
kFmtRegR, 4, 0, kFmtRegROrSp, 9, 5, kFmtBitBlt, 21, 10,
kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index ddfec2d..d81091d 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -337,13 +337,13 @@
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
- (static_cast<size_t>(frame_size_) <
- Thread::kStackOverflowReservedBytes));
+ bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !IsLargeFrame(frame_size_, kArm64);
NewLIR0(kPseudoMethodEntry);
- const bool large_frame = (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes);
+ constexpr size_t kStackOverflowReservedUsableBytes = kArm64StackOverflowReservedBytes -
+ Thread::kStackOverflowSignalReservedBytes;
+ const bool large_frame = static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes;
const int spill_count = num_core_spills_ + num_fp_spills_;
const int spill_size = (spill_count * kArm64PointerSize + 15) & ~0xf; // SP 16 byte alignment.
const int frame_size_without_spills = frame_size_ - spill_size;
@@ -412,7 +412,7 @@
// Branch to throw target if there is not enough room.
OpRegRegImm(kOpSub, rs_x9, rs_rA64_SP, frame_size_without_spills);
LoadWordDisp(rs_rA64_SELF, Thread::StackEndOffset<8>().Int32Value(), rs_x8);
- LIR* branch = OpCmpBranch(kCondUlt, rs_rA64_SP, rs_x8, nullptr);
+ LIR* branch = OpCmpBranch(kCondUlt, rs_x9, rs_x8, nullptr);
AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, spill_size));
OpRegCopy(rs_rA64_SP, rs_x9); // Establish stack after checks.
} else {
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index b1b83f0..0fa7f2b 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -87,7 +87,9 @@
OpSize size) OVERRIDE;
LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
RegStorage r_src, OpSize size) OVERRIDE;
- void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+ void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) OVERRIDE;
+ LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
+ int offset, int check_value, LIR* target) OVERRIDE;
// Required for target - register utilities.
RegStorage TargetReg(SpecialTargetRegister reg);
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index 2c6b11d..2ac4adb 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -160,6 +160,19 @@
return branch;
}
+LIR* Arm64Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg,
+ RegStorage base_reg, int offset, int check_value,
+ LIR* target) {
+ // It is possible that temp register is 64-bit. (ArgReg or RefReg)
+ // Always compare 32-bit value no matter what temp_reg is.
+ if (temp_reg.Is64Bit()) {
+ temp_reg = As32BitReg(temp_reg);
+ }
+ Load32Disp(base_reg, offset, temp_reg);
+ LIR* branch = OpCmpImmBranch(cond, temp_reg, check_value, target);
+ return branch;
+}
+
LIR* Arm64Mir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
bool dest_is_fp = r_dest.IsFloat();
bool src_is_fp = r_src.IsFloat();
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 2254b8b..b3ca7c4 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -99,7 +99,8 @@
LIR* data_target = ScanLiteralPool(literal_list_, value, 0);
if (data_target == NULL) {
- data_target = AddWordData(&literal_list_, value);
+ // Wide, as we need 8B alignment.
+ data_target = AddWideData(&literal_list_, value, 0);
}
ScopedMemRefType mem_ref_type(this, ResourceMask::kLiteral);
@@ -660,6 +661,7 @@
int32_t log_imm = -1;
bool is_wide = r_dest.Is64Bit();
ArmOpcode wide = (is_wide) ? WIDE(0) : UNWIDE(0);
+ int info = 0;
switch (op) {
case kOpLsl: {
@@ -692,7 +694,14 @@
return NewLIR4(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), abs_value >> 12, 1);
} else {
log_imm = -1;
- alt_opcode = (neg) ? kA64Add4rrro : kA64Sub4rrro;
+ alt_opcode = (neg) ? kA64Add4rrre : kA64Sub4rrre;
+ // To make it correct, we need:
+ // 23..21 = 001 = extend
+ // 15..13 = 01x = LSL/UXTW/X / x defines wide or not
+ // 12..10 = 000 = no shift (in case of SP)
+ // => info = 00101x000
+ // => =0x 0 5 (0/8)
+ info = (is_wide ? 8 : 0) | 0x50;
}
break;
// case kOpRsub:
@@ -734,7 +743,7 @@
if (log_imm >= 0) {
return NewLIR3(opcode | wide, r_dest.GetReg(), r_src1.GetReg(), log_imm);
} else {
- RegStorage r_scratch = AllocTemp();
+ RegStorage r_scratch;
if (IS_WIDE(wide)) {
r_scratch = AllocTempWide();
LoadConstantWide(r_scratch, value);
@@ -743,7 +752,7 @@
LoadConstant(r_scratch, value);
}
if (EncodingMap[alt_opcode].flags & IS_QUAD_OP)
- res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), 0);
+ res = NewLIR4(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg(), info);
else
res = NewLIR3(alt_opcode | wide, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
FreeTemp(r_scratch);
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 6397208..3f9379c 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -292,10 +292,14 @@
return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
}
-bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
+bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) {
ReaderMutexLock mu(Thread::Current(), lock_);
auto it = inline_methods_.find(method_index);
- return it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0;
+ bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0);
+ if (res && intrinsic != nullptr) {
+ *intrinsic = it->second;
+ }
+ return res;
}
bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index c03f89c..70693c2 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -67,7 +67,7 @@
/**
* Check whether a particular method index corresponds to an intrinsic function.
*/
- bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_);
+ bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) LOCKS_EXCLUDED(lock_);
/**
* Generate code for an intrinsic function invocation.
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index c734202..e53105f 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -305,8 +305,7 @@
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
- (static_cast<size_t>(frame_size_) < Thread::kStackOverflowReservedBytes));
+ bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !IsLargeFrame(frame_size_, kMips);
NewLIR0(kPseudoMethodEntry);
RegStorage check_reg = AllocTemp();
RegStorage new_sp = AllocTemp();
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 9155677..f70087d 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -25,6 +25,7 @@
#include "dex/backend.h"
#include "dex/quick/resource_mask.h"
#include "driver/compiler_driver.h"
+#include "instruction_set.h"
#include "leb128.h"
#include "safe_map.h"
#include "utils/array_ref.h"
@@ -206,6 +207,36 @@
#define SLOW_TYPE_PATH (cu_->enable_debug & (1 << kDebugSlowTypePath))
#define EXERCISE_SLOWEST_STRING_PATH (cu_->enable_debug & (1 << kDebugSlowestStringPath))
+// Size of a frame that we definitely consider large. Anything larger than this should
+// definitely get a stack overflow check.
+static constexpr size_t kLargeFrameSize = 2 * KB;
+
+// Size of a frame that should be small. Anything leaf method smaller than this should run
+// without a stack overflow check.
+// The constant is from experience with frameworks code.
+static constexpr size_t kSmallFrameSize = 1 * KB;
+
+// Determine whether a frame is small or large, used in the decision on whether to elide a
+// stack overflow check on method entry.
+//
+// A frame is considered large when it's either above kLargeFrameSize, or a quarter of the
+// overflow-usable stack space.
+static constexpr bool IsLargeFrame(size_t size, InstructionSet isa) {
+ return size >= kLargeFrameSize || size >= GetStackOverflowReservedBytes(isa) / 4;
+}
+
+// We want to ensure that on all systems kSmallFrameSize will lead to false in IsLargeFrame.
+COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kArm),
+ kSmallFrameSize_is_not_a_small_frame_arm);
+COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kArm64),
+ kSmallFrameSize_is_not_a_small_frame_arm64);
+COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kMips),
+ kSmallFrameSize_is_not_a_small_frame_mips);
+COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kX86),
+ kSmallFrameSize_is_not_a_small_frame_x86);
+COMPILE_ASSERT(!IsLargeFrame(kSmallFrameSize, kX86_64),
+ kSmallFrameSize_is_not_a_small_frame_x64_64);
+
class Mir2Lir : public Backend {
public:
/*
@@ -953,8 +984,8 @@
bool GenInlinedReverseBytes(CallInfo* info, OpSize size);
bool GenInlinedAbsInt(CallInfo* info);
virtual bool GenInlinedAbsLong(CallInfo* info);
- bool GenInlinedAbsFloat(CallInfo* info);
- bool GenInlinedAbsDouble(CallInfo* info);
+ virtual bool GenInlinedAbsFloat(CallInfo* info);
+ virtual bool GenInlinedAbsDouble(CallInfo* info);
bool GenInlinedFloatCvt(CallInfo* info);
bool GenInlinedDoubleCvt(CallInfo* info);
virtual bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index dd5dab2..28195ab 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -235,8 +235,8 @@
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- const bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
- (static_cast<size_t>(frame_size_) < Thread::kStackOverflowReservedBytes));
+ const bool skip_overflow_check = mir_graph_->MethodIsLeaf() &&
+ !IsLargeFrame(frame_size_, Gen64Bit() ? kX86_64 : kX86);
NewLIR0(kPseudoMethodEntry);
/* Spill core callee saves */
SpillCoreRegs();
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index d874aaa..d482e58 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -155,6 +155,8 @@
bool GenInlinedCas(CallInfo* info, bool is_long, bool is_object);
bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
bool GenInlinedSqrt(CallInfo* info);
+ bool GenInlinedAbsFloat(CallInfo* info) OVERRIDE;
+ bool GenInlinedAbsDouble(CallInfo* info) OVERRIDE;
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNotLong(RegLocation rl_dest, RegLocation rl_src);
@@ -796,6 +798,14 @@
*/
void AnalyzeDoubleUse(RegLocation rl_use);
+ /*
+ * @brief Analyze one invoke-static MIR instruction
+ * @param opcode MIR instruction opcode.
+ * @param bb Basic block containing instruction.
+ * @param mir Instruction to analyze.
+ */
+ void AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir);
+
bool Gen64Bit() const { return gen64bit_; }
// Information derived from analysis of MIR
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 458f9c6..20bb7bf 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -587,5 +587,107 @@
return true;
}
+bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
+ // Get the argument
+ RegLocation rl_src = info->args[0];
+
+ // Get the inlined intrinsic target virtual register
+ RegLocation rl_dest = InlineTarget(info);
+
+ // Get the virtual register number
+ DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
+ int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+
+ // if argument is the same as inlined intrinsic target
+ if (v_src_reg == v_dst_reg) {
+ rl_src = UpdateLoc(rl_src);
+
+ // if argument is in the physical register
+ if (rl_src.location == kLocPhysReg) {
+ rl_src = LoadValue(rl_src, kCoreReg);
+ OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
+ StoreValue(rl_dest, rl_src);
+ return true;
+ }
+ // the argument is in memory
+ DCHECK((rl_src.location == kLocDalvikFrame) ||
+ (rl_src.location == kLocCompilerTemp));
+
+ // Operate directly into memory.
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+ ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+ LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement, 0x7fffffff);
+ AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
+ AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
+ return true;
+ } else {
+ rl_src = LoadValue(rl_src, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
+ StoreValue(rl_dest, rl_result);
+ return true;
+ }
+}
+
+bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
+ RegLocation rl_src = info->args[0];
+ RegLocation rl_dest = InlineTargetWide(info);
+ DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
+ int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+ rl_src = UpdateLocWide(rl_src);
+
+ // if argument is in the physical XMM register
+ if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
+ RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
+ if (rl_result.reg != rl_src.reg) {
+ LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
+ NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
+ } else {
+ RegStorage sign_mask = AllocTempDouble();
+ LoadConstantWide(sign_mask, 0x7fffffffffffffff);
+ NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
+ FreeTemp(sign_mask);
+ }
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+ } else if (v_src_reg == v_dst_reg) {
+ // if argument is the same as inlined intrinsic target
+ // if argument is in the physical register
+ if (rl_src.location == kLocPhysReg) {
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
+ StoreValueWide(rl_dest, rl_src);
+ return true;
+ }
+ // the argument is in memory
+ DCHECK((rl_src.location == kLocDalvikFrame) ||
+ (rl_src.location == kLocCompilerTemp));
+
+ // Operate directly into memory.
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+ ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+ LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
+ return true;
+ } else {
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ OpRegCopyWide(rl_result.reg, rl_src.reg);
+ OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+ }
+}
} // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 2948e56..078dd5a 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -441,6 +441,31 @@
Clobber(rs_rCX);
Clobber(rs_rDX);
Clobber(rs_rBX);
+
+ Clobber(rs_fr0);
+ Clobber(rs_fr1);
+ Clobber(rs_fr2);
+ Clobber(rs_fr3);
+ Clobber(rs_fr4);
+ Clobber(rs_fr5);
+ Clobber(rs_fr6);
+ Clobber(rs_fr7);
+
+ if (Gen64Bit()) {
+ Clobber(rs_r8);
+ Clobber(rs_r9);
+ Clobber(rs_r10);
+ Clobber(rs_r11);
+
+ Clobber(rs_fr8);
+ Clobber(rs_fr9);
+ Clobber(rs_fr10);
+ Clobber(rs_fr11);
+ Clobber(rs_fr12);
+ Clobber(rs_fr13);
+ Clobber(rs_fr14);
+ Clobber(rs_fr15);
+ }
}
RegLocation X86Mir2Lir::GetReturnWideAlt() {
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index b93e3e8..46e877f 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -18,6 +18,8 @@
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/dataflow_iterator-inl.h"
#include "x86_lir.h"
+#include "dex/quick/dex_file_method_inliner.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
namespace art {
@@ -953,6 +955,9 @@
case Instruction::PACKED_SWITCH:
store_method_addr_ = true;
break;
+ case Instruction::INVOKE_STATIC:
+ AnalyzeInvokeStatic(opcode, bb, mir);
+ break;
default:
// Other instructions are not interesting yet.
break;
@@ -1020,4 +1025,22 @@
DCHECK(CheckCorePoolSanity());
return loc;
}
+
+void X86Mir2Lir::AnalyzeInvokeStatic(int opcode, BasicBlock * bb, MIR *mir) {
+ uint32_t index = mir->dalvikInsn.vB;
+ if (!(mir->optimization_flags & MIR_INLINED)) {
+ DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
+ InlineMethod method;
+ if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
+ ->IsIntrinsic(index, &method)) {
+ switch (method.opcode) {
+ case kIntrinsicAbsDouble:
+ store_method_addr_ = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
} // namespace art
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index f81e2f9..2a82129 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -22,6 +22,7 @@
#include "globals.h"
#include "base/logging.h"
#include "base/hex_dump.h"
+#include "instruction_set.h"
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
#include "thread.h"
@@ -59,7 +60,7 @@
// get the method from the top of the stack. However it's in r0.
uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(sc->fault_address);
uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
- reinterpret_cast<uint8_t*>(*out_sp) - Thread::kStackOverflowReservedBytes);
+ reinterpret_cast<uint8_t*>(*out_sp) - kArmStackOverflowReservedBytes);
if (overflow_addr == fault_addr) {
*out_method = reinterpret_cast<mirror::ArtMethod*>(sc->arm_r0);
} else {
@@ -190,7 +191,7 @@
VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
", fault_addr: " << fault_addr;
- uintptr_t overflow_addr = sp - Thread::kStackOverflowReservedBytes;
+ uintptr_t overflow_addr = sp - kArmStackOverflowReservedBytes;
Thread* self = reinterpret_cast<Thread*>(sc->arm_r9);
CHECK_EQ(self, Thread::Current());
diff --git a/runtime/atomic.cc b/runtime/atomic.cc
index 63f2cf8..e766a8d 100644
--- a/runtime/atomic.cc
+++ b/runtime/atomic.cc
@@ -31,7 +31,7 @@
if (kNeedSwapMutexes) {
gSwapMutexes = new std::vector<Mutex*>;
for (size_t i = 0; i < kSwapMutexCount; ++i) {
- gSwapMutexes->push_back(new Mutex("QuasiAtomic stripe"));
+ gSwapMutexes->push_back(new Mutex("QuasiAtomic stripe", kSwapMutexesLock));
}
}
}
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 1ba6180..81e62ab 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -55,6 +55,7 @@
enum LockLevel {
kLoggingLock = 0,
kMemMapsLock,
+ kSwapMutexesLock,
kUnexpectedSignalLock,
kThreadSuspendCountLock,
kAbortLock,
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 3d8b29f..ff836a4 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -511,13 +511,8 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtField* resolved_field =
referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
- if (UNLIKELY(resolved_field == NULL)) {
- return NULL;
- }
- mirror::Class* fields_class = resolved_field->GetDeclaringClass();
- // Check class is initiliazed or initializing.
- if (UNLIKELY(!fields_class->IsInitializing())) {
- return NULL;
+ if (UNLIKELY(resolved_field == nullptr)) {
+ return nullptr;
}
// Check for incompatible class change.
bool is_primitive;
@@ -541,7 +536,15 @@
}
if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
// Incompatible class change.
- return NULL;
+ return nullptr;
+ }
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ if (is_static) {
+ // Check class is initialized else fail so that we can contend to initialize the class with
+ // other threads that may be racing to do this.
+ if (UNLIKELY(!fields_class->IsInitialized())) {
+ return nullptr;
+ }
}
mirror::Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
@@ -549,11 +552,11 @@
resolved_field->GetAccessFlags()) ||
(is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
// Illegal access.
- return NULL;
+ return nullptr;
}
if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
resolved_field->FieldSize() != expected_size)) {
- return NULL;
+ return nullptr;
}
return resolved_field;
}
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index f2e2bf7..329c175 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -33,7 +33,7 @@
// Ensure static methods are initialized.
if (method->IsStatic()) {
mirror::Class* declaringClass = method->GetDeclaringClass();
- if (UNLIKELY(!declaringClass->IsInitializing())) {
+ if (UNLIKELY(!declaringClass->IsInitialized())) {
self->PushShadowFrame(shadow_frame);
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(declaringClass));
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 6825e78..2da016f 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -213,7 +213,7 @@
self->PushShadowFrame(shadow_frame);
self->EndAssertNoThreadSuspension(old_cause);
- if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
+ if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) {
// Ensure static method's class is initialized.
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 514d1aa..7a144b6 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -484,7 +484,7 @@
self->PushShadowFrame(shadow_frame);
self->EndAssertNoThreadSuspension(old_cause);
- if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
+ if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) {
// Ensure static method's class is initialized.
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index 67e7100..96eeb8d 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -22,6 +22,7 @@
#include "base/logging.h" // Logging is required for FATAL in the helper functions.
#include "base/macros.h"
+#include "globals.h" // For KB.
namespace art {
@@ -36,6 +37,20 @@
};
std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
+#if defined(__arm__)
+static constexpr InstructionSet kRuntimeISA = kArm;
+#elif defined(__aarch64__)
+static constexpr InstructionSet kRuntimeISA = kArm64;
+#elif defined(__mips__)
+static constexpr InstructionSet kRuntimeISA = kMips;
+#elif defined(__i386__)
+static constexpr InstructionSet kRuntimeISA = kX86;
+#elif defined(__x86_64__)
+static constexpr InstructionSet kRuntimeISA = kX86_64;
+#else
+static constexpr InstructionSet kRuntimeISA = kNone;
+#endif
+
// Architecture-specific pointer sizes
static constexpr size_t kArmPointerSize = 4;
static constexpr size_t kArm64PointerSize = 8;
@@ -153,19 +168,33 @@
}
}
-#if defined(__arm__)
-static constexpr InstructionSet kRuntimeISA = kArm;
-#elif defined(__aarch64__)
-static constexpr InstructionSet kRuntimeISA = kArm64;
-#elif defined(__mips__)
-static constexpr InstructionSet kRuntimeISA = kMips;
-#elif defined(__i386__)
-static constexpr InstructionSet kRuntimeISA = kX86;
-#elif defined(__x86_64__)
-static constexpr InstructionSet kRuntimeISA = kX86_64;
-#else
-static constexpr InstructionSet kRuntimeISA = kNone;
-#endif
+static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
+static constexpr size_t kArmStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+
+// TODO: shrink reserved space, in particular for 64bit.
+
+// Worst-case, we would need about 2.6x the amount of x86_64 for many more registers.
+// But this one works rather well.
+static constexpr size_t kArm64StackOverflowReservedBytes = 32 * KB;
+// TODO: Bumped to workaround regression (http://b/14982147) Specifically to fix:
+// test-art-host-run-test-interpreter-018-stack-overflow
+// test-art-host-run-test-interpreter-107-int-math2
+static constexpr size_t kX86StackOverflowReservedBytes = 24 * KB;
+static constexpr size_t kX86_64StackOverflowReservedBytes = 32 * KB;
+
+static constexpr size_t GetStackOverflowReservedBytes(InstructionSet isa) {
+ return (isa == kArm || isa == kThumb2) ? kArmStackOverflowReservedBytes :
+ isa == kArm64 ? kArm64StackOverflowReservedBytes :
+ isa == kMips ? kMipsStackOverflowReservedBytes :
+ isa == kX86 ? kX86StackOverflowReservedBytes :
+ isa == kX86_64 ? kX86_64StackOverflowReservedBytes :
+ isa == kNone ? (LOG(FATAL) << "kNone has no stack overflow size", 0) :
+ (LOG(FATAL) << "Unknown instruction set" << isa, 0);
+}
+
+static constexpr size_t kRuntimeStackOverflowReservedBytes =
+ GetStackOverflowReservedBytes(kRuntimeISA);
enum InstructionFeatures {
kHwDiv = 0x1, // Supports hardware divide.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 6dbc6a0..cb4d444 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -454,7 +454,7 @@
}
self->EndAssertNoThreadSuspension(old_cause);
// Do this after populating the shadow frame in case EnsureInitialized causes a GC.
- if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitializing())) {
+ if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitialized())) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
@@ -527,7 +527,7 @@
// Ensure static methods are initialized.
if (method->IsStatic()) {
mirror::Class* declaring_class = method->GetDeclaringClass();
- if (UNLIKELY(!declaring_class->IsInitializing())) {
+ if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(self);
HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 66406bf..5606d47 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -135,6 +135,8 @@
mirror::ArtMethod* method = nullptr;
if (is_static) {
method = c->FindDirectMethod(name, sig);
+ } else if (c->IsInterface()) {
+ method = c->FindInterfaceMethod(name, sig);
} else {
method = c->FindVirtualMethod(name, sig);
if (method == nullptr) {
@@ -3312,8 +3314,7 @@
void* JavaVMExt::FindCodeForNativeMethod(mirror::ArtMethod* m) {
CHECK(m->IsNative());
mirror::Class* c = m->GetDeclaringClass();
- // If this is a static method, it could be called before the class
- // has been initialized.
+ // If this is a static method, it could be called before the class has been initialized.
if (m->IsStatic()) {
c = EnsureInitialized(Thread::Current(), c);
if (c == nullptr) {
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index f182e95..5e46c57 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -268,32 +268,38 @@
jclass jlobject = env_->FindClass("java/lang/Object");
jclass jlstring = env_->FindClass("java/lang/String");
jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
+ jclass jncrbc = env_->FindClass("java/nio/channels/ReadableByteChannel");
- // Sanity check that no exceptions are pending
+ // Sanity check that no exceptions are pending.
ASSERT_FALSE(env_->ExceptionCheck());
// Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
- // a pending exception
+ // a pending exception.
jmethodID method = env_->GetMethodID(jlobject, "foo", "()V");
EXPECT_EQ(nullptr, method);
ExpectException(jlnsme);
- // Check that java.lang.Object.equals() does exist
+ // Check that java.lang.Object.equals() does exist.
method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
EXPECT_NE(nullptr, method);
EXPECT_FALSE(env_->ExceptionCheck());
// Check that GetMethodID for java.lang.String.valueOf(int) fails as the
- // method is static
+ // method is static.
method = env_->GetMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
EXPECT_EQ(nullptr, method);
ExpectException(jlnsme);
- // Check that GetMethodID for java.lang.NoSuchMethodError.<init>(String) finds the constructor
+ // Check that GetMethodID for java.lang.NoSuchMethodError.<init>(String) finds the constructor.
method = env_->GetMethodID(jlnsme, "<init>", "(Ljava/lang/String;)V");
EXPECT_NE(nullptr, method);
EXPECT_FALSE(env_->ExceptionCheck());
+ // Check that GetMethodID can find a interface method inherited from another interface.
+ method = env_->GetMethodID(jncrbc, "close", "()V");
+ EXPECT_NE(nullptr, method);
+ EXPECT_FALSE(env_->ExceptionCheck());
+
// Bad arguments.
CheckJniAbortCatcher check_jni_abort_catcher;
method = env_->GetMethodID(nullptr, "<init>", "(Ljava/lang/String;)V");
@@ -630,11 +636,13 @@
jni_abort_catcher.Check(
"attempt to get double primitive array elements with an object of type boolean[]");
jbyteArray array2 = env_->NewByteArray(10);
- EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy), nullptr);
+ EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy),
+ nullptr);
jni_abort_catcher.Check(
"attempt to get boolean primitive array elements with an object of type byte[]");
jobject object = env_->NewStringUTF("Test String");
- EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy), nullptr);
+ EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy),
+ nullptr);
jni_abort_catcher.Check(
"attempt to get boolean primitive array elements with an object of type java.lang.String");
}
@@ -681,7 +689,8 @@
jobject object = env_->NewStringUTF("Test String");
env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
jni_abort_catcher.Check(
- "attempt to release boolean primitive array elements with an object of type java.lang.String");
+ "attempt to release boolean primitive array elements with an object of type "
+ "java.lang.String");
}
TEST_F(JniInternalTest, GetReleasePrimitiveArrayCriticalOfWrongType) {
CheckJniAbortCatcher jni_abort_catcher;
@@ -736,7 +745,8 @@
env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
reinterpret_cast<jboolean*>(elements));
jni_abort_catcher.Check(
- "attempt to get region of boolean primitive array elements with an object of type java.lang.String");
+ "attempt to get region of boolean primitive array elements with an object of type "
+ "java.lang.String");
}
TEST_F(JniInternalTest, SetPrimitiveArrayRegionElementsOfWrongType) {
@@ -782,7 +792,8 @@
env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
reinterpret_cast<jboolean*>(elements));
jni_abort_catcher.Check(
- "attempt to set region of boolean primitive array elements with an object of type java.lang.String");
+ "attempt to set region of boolean primitive array elements with an object of type "
+ "java.lang.String");
}
TEST_F(JniInternalTest, NewObjectArray) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a20f7b9..c798180 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -37,17 +37,17 @@
namespace art {
namespace mirror {
-Class* Class::java_lang_Class_ = NULL;
+Class* Class::java_lang_Class_ = nullptr;
void Class::SetClassClass(Class* java_lang_Class) {
- CHECK(java_lang_Class_ == NULL) << java_lang_Class_ << " " << java_lang_Class;
- CHECK(java_lang_Class != NULL);
+ CHECK(java_lang_Class_ == nullptr) << java_lang_Class_ << " " << java_lang_Class;
+ CHECK(java_lang_Class != nullptr);
java_lang_Class_ = java_lang_Class;
}
void Class::ResetClass() {
- CHECK(java_lang_Class_ != NULL);
- java_lang_Class_ = NULL;
+ CHECK(java_lang_Class_ != nullptr);
+ java_lang_Class_ = nullptr;
}
void Class::VisitRoots(RootCallback* callback, void* arg) {
@@ -146,7 +146,7 @@
if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
// The descriptor indicates that this is the class for
// a primitive type; special-case the return value.
- const char* c_name = NULL;
+ const char* c_name = nullptr;
switch (descriptor[0]) {
case 'Z': c_name = "boolean"; break;
case 'B': c_name = "byte"; break;
@@ -196,10 +196,10 @@
os << "----- " << (IsInterface() ? "interface" : "class") << " "
<< "'" << GetDescriptor() << "' cl=" << GetClassLoader() << " -----\n",
os << " objectSize=" << SizeOf() << " "
- << "(" << (h_super.Get() != NULL ? h_super->SizeOf() : -1) << " from super)\n",
+ << "(" << (h_super.Get() != nullptr ? h_super->SizeOf() : -1) << " from super)\n",
os << StringPrintf(" access=0x%04x.%04x\n",
GetAccessFlags() >> 16, GetAccessFlags() & kAccJavaFlagsMask);
- if (h_super.Get() != NULL) {
+ if (h_super.Get() != nullptr) {
os << " super='" << PrettyClass(h_super.Get()) << "' (cl=" << h_super->GetClassLoader()
<< ")\n";
}
@@ -217,7 +217,7 @@
}
// After this point, this may have moved due to GetDirectInterface.
os << " vtable (" << h_this->NumVirtualMethods() << " entries, "
- << (h_super.Get() != NULL ? h_super->NumVirtualMethods() : 0) << " in super):\n";
+ << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
for (size_t i = 0; i < NumVirtualMethods(); ++i) {
os << StringPrintf(" %2zd: %s\n", i,
PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str());
@@ -253,7 +253,7 @@
// Sanity check that the number of bits set in the reference offset bitmap
// agrees with the number of references
size_t count = 0;
- for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ for (Class* c = this; c != nullptr; c = c->GetSuperClass()) {
count += c->NumReferenceInstanceFieldsDuringLinking();
}
CHECK_EQ((size_t)POPCOUNT(new_reference_offsets), count);
@@ -329,40 +329,58 @@
}
}
-ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) {
+ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) {
// Check the current class before checking the interfaces.
ArtMethod* method = FindDeclaredVirtualMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
int32_t iftable_count = GetIfTableCount();
IfTable* iftable = GetIfTable();
- for (int32_t i = 0; i < iftable_count; i++) {
+ for (int32_t i = 0; i < iftable_count; ++i) {
method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
+}
+
+ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) {
+ // Check the current class before checking the interfaces.
+ ArtMethod* method = FindDeclaredVirtualMethod(name, signature);
+ if (method != nullptr) {
+ return method;
+ }
+
+ int32_t iftable_count = GetIfTableCount();
+ IfTable* iftable = GetIfTable();
+ for (int32_t i = 0; i < iftable_count; ++i) {
+ method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(name, signature);
+ if (method != nullptr) {
+ return method;
+ }
+ }
+ return nullptr;
}
ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) {
// Check the current class before checking the interfaces.
ArtMethod* method = FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
int32_t iftable_count = GetIfTableCount();
IfTable* iftable = GetIfTable();
- for (int32_t i = 0; i < iftable_count; i++) {
+ for (int32_t i = 0; i < iftable_count; ++i) {
method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) {
@@ -372,7 +390,7 @@
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) {
@@ -382,7 +400,7 @@
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) {
@@ -394,37 +412,37 @@
}
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) {
@@ -434,7 +452,7 @@
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) {
@@ -444,7 +462,7 @@
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) {
@@ -456,37 +474,37 @@
}
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
- if (method != NULL) {
+ if (method != nullptr) {
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtMethod* Class::FindClassInitializer() {
@@ -498,7 +516,7 @@
return method;
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) {
@@ -510,7 +528,7 @@
return f;
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindDeclaredInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx) {
@@ -522,42 +540,42 @@
}
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindInstanceField(const StringPiece& name, const StringPiece& type) {
// Is the field in this class, or any of its superclasses?
// Interfaces are not relevant because they can't contain instance fields.
- for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ for (Class* c = this; c != nullptr; c = c->GetSuperClass()) {
ArtField* f = c->FindDeclaredInstanceField(name, type);
- if (f != NULL) {
+ if (f != nullptr) {
return f;
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindInstanceField(const DexCache* dex_cache, uint32_t dex_field_idx) {
// Is the field in this class, or any of its superclasses?
// Interfaces are not relevant because they can't contain instance fields.
- for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ for (Class* c = this; c != nullptr; c = c->GetSuperClass()) {
ArtField* f = c->FindDeclaredInstanceField(dex_cache, dex_field_idx);
- if (f != NULL) {
+ if (f != nullptr) {
return f;
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& type) {
- DCHECK(type != NULL);
+ DCHECK(type != nullptr);
for (size_t i = 0; i < NumStaticFields(); ++i) {
ArtField* f = GetStaticField(i);
if (name == f->GetName() && type == f->GetTypeDescriptor()) {
return f;
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindDeclaredStaticField(const DexCache* dex_cache, uint32_t dex_field_idx) {
@@ -569,7 +587,7 @@
}
}
}
- return NULL;
+ return nullptr;
}
ArtField* Class::FindStaticField(Thread* self, Handle<Class> klass, const StringPiece& name,
@@ -603,7 +621,7 @@
for (Class* k = klass.Get(); k != nullptr; k = k->GetSuperClass()) {
// Is the field in this class?
ArtField* f = k->FindDeclaredStaticField(dex_cache, dex_field_idx);
- if (f != NULL) {
+ if (f != nullptr) {
return f;
}
// Wrap k incase it moves during GetDirectInterface.
@@ -625,7 +643,7 @@
ArtField* Class::FindField(Thread* self, Handle<Class> klass, const StringPiece& name,
const StringPiece& type) {
// Find a field using the JLS field resolution order
- for (Class* k = klass.Get(); k != NULL; k = k->GetSuperClass()) {
+ for (Class* k = klass.Get(); k != nullptr; k = k->GetSuperClass()) {
// Is the field in this class?
ArtField* f = k->FindDeclaredInstanceField(name, type);
if (f != nullptr) {
@@ -652,10 +670,10 @@
static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::ArtMethod>* methods)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (methods != NULL) {
+ if (methods != nullptr) {
for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
mirror::ArtMethod* method = methods->GetWithoutChecks(index);
- DCHECK(method != NULL);
+ DCHECK(method != nullptr);
if (!method->IsNative() && !method->IsAbstract()) {
method->SetPreverified();
}
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 90381a7..c83f411 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -648,6 +648,9 @@
ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ArtMethod* FindInterfaceMethod(const StringPiece& name, const StringPiece& signature)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 6980530..3f8f4a3 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -220,7 +220,7 @@
// It's likely that callers are trying to ensure they have at least a certain amount of
// stack space, so we should add our reserved space on top of what they requested, rather
// than implicitly take it away from them.
- stack_size += Thread::kStackOverflowReservedBytes;
+ stack_size += kRuntimeStackOverflowReservedBytes;
} else {
// If we are going to use implicit stack checks, allocate space for the protected
// region at the bottom of the stack.
@@ -489,7 +489,7 @@
tlsPtr_.stack_begin = reinterpret_cast<byte*>(read_stack_base);
tlsPtr_.stack_size = read_stack_size;
- if (read_stack_size <= kStackOverflowReservedBytes) {
+ if (read_stack_size <= kRuntimeStackOverflowReservedBytes) {
LOG(FATAL) << "Attempt to attach a thread with a too-small stack (" << read_stack_size
<< " bytes)";
}
@@ -2200,7 +2200,7 @@
if (tlsPtr_.stack_end == tlsPtr_.stack_begin) {
// However, we seem to have already extended to use the full stack.
LOG(ERROR) << "Need to increase kStackOverflowReservedBytes (currently "
- << kStackOverflowReservedBytes << ")?";
+ << kRuntimeStackOverflowReservedBytes << ")?";
DumpStack(LOG(ERROR));
LOG(FATAL) << "Recursive stack overflow.";
}
diff --git a/runtime/thread.h b/runtime/thread.h
index bff9b52..7cd86de 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -33,6 +33,7 @@
#include "gc/allocator/rosalloc.h"
#include "globals.h"
#include "handle_scope.h"
+#include "instruction_set.h"
#include "jvalue.h"
#include "object_callbacks.h"
#include "offsets.h"
@@ -94,28 +95,8 @@
class Thread {
public:
- // Space to throw a StackOverflowError in.
- // TODO: shrink reserved space, in particular for 64bit.
-#if defined(__x86_64__)
- static constexpr size_t kStackOverflowReservedBytes = 32 * KB;
-#elif defined(__aarch64__)
- // Worst-case, we would need about 2.6x the amount of x86_64 for many more registers.
- // But this one works rather well.
- static constexpr size_t kStackOverflowReservedBytes = 32 * KB;
-#elif defined(__i386__)
- // TODO: Bumped to workaround regression (http://b/14982147) Specifically to fix:
- // test-art-host-run-test-interpreter-018-stack-overflow
- // test-art-host-run-test-interpreter-107-int-math2
- static constexpr size_t kStackOverflowReservedBytes = 24 * KB;
-#else
- static constexpr size_t kStackOverflowReservedBytes = 16 * KB;
-#endif
// How much of the reserved bytes is reserved for incoming signals.
static constexpr size_t kStackOverflowSignalReservedBytes = 2 * KB;
- // How much of the reserved bytes we may temporarily use during stack overflow checks as an
- // optimization.
- static constexpr size_t kStackOverflowReservedUsableBytes =
- kStackOverflowReservedBytes - kStackOverflowSignalReservedBytes;
// For implicit overflow checks we reserve an extra piece of memory at the bottom
// of the stack (lowest memory). The higher portion of the memory
@@ -123,7 +104,7 @@
// throwing the StackOverflow exception.
static constexpr size_t kStackOverflowProtectedSize = 16 * KB;
static constexpr size_t kStackOverflowImplicitCheckSize = kStackOverflowProtectedSize +
- kStackOverflowReservedBytes;
+ kRuntimeStackOverflowReservedBytes;
// Creates a new native thread corresponding to the given managed peer.
// Used to implement Thread.start.
@@ -585,7 +566,7 @@
// overflow region.
tlsPtr_.stack_end = tlsPtr_.stack_begin + kStackOverflowImplicitCheckSize;
} else {
- tlsPtr_.stack_end = tlsPtr_.stack_begin + kStackOverflowReservedBytes;
+ tlsPtr_.stack_end = tlsPtr_.stack_begin + kRuntimeStackOverflowReservedBytes;
}
}