MIPS: Shorten .bss string/class loads
This is a follow-up to
https://android-review.googlesource.com/#/c/384033/.
Test: booted MIPS64 (with 2nd arch MIPS32R6) in QEMU
Test: testrunner.py --target --optimizing
Test: same tests as above on CI20
Test: booted MIPS32R2 and MIPS64 in QEMU in configurations:
ART_USE_READ_BARRIER=false,
ART_READ_BARRIER_TYPE=TABLELOOKUP
Change-Id: I4cb2f4ded13c0d9fc960c7eac55396f7931c1e38
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index d99d237..3bec30f 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -49,43 +49,27 @@
uint32_t target_offset) {
uint32_t anchor_literal_offset = patch.PcInsnOffset();
uint32_t literal_offset = patch.LiteralOffset();
- uint32_t literal_low_offset;
+ bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
- // Perform basic sanity checks and initialize `literal_low_offset` to point
- // to the instruction containing the 16 least significant bits of the
- // relative address.
- if (is_r6) {
- DCHECK_GE(code->size(), 8u);
- DCHECK_LE(literal_offset, code->size() - 8u);
- DCHECK_EQ(literal_offset, anchor_literal_offset);
- // AUIPC reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
- DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
- // instr reg(s), offset_low
- DCHECK_EQ((*code)[literal_offset + 4], 0x78);
- DCHECK_EQ((*code)[literal_offset + 5], 0x56);
- literal_low_offset = literal_offset + 4;
+ // Perform basic sanity checks.
+ if (high_patch) {
+ if (is_r6) {
+ // auipc reg, offset_high
+ DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
+ DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
+ } else {
+ // lui reg, offset_high
+ DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
+ DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
+ // addu reg, reg, reg2
+ DCHECK_EQ((*code)[literal_offset + 4], 0x21);
+ DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
+ DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
+ }
} else {
- DCHECK_GE(code->size(), 16u);
- DCHECK_LE(literal_offset, code->size() - 12u);
- DCHECK_GE(literal_offset, 4u);
- // The NAL instruction does not precede immediately as the PC+0
- // comes from HMipsComputeBaseMethodAddress.
- // LUI reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
- DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
- // ADDU reg, reg, reg2
- DCHECK_EQ((*code)[literal_offset + 4], 0x21);
- DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
- DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
// instr reg(s), offset_low
- DCHECK_EQ((*code)[literal_offset + 8], 0x78);
- DCHECK_EQ((*code)[literal_offset + 9], 0x56);
- literal_low_offset = literal_offset + 8;
+ CHECK_EQ((*code)[literal_offset + 0], 0x78);
+ CHECK_EQ((*code)[literal_offset + 1], 0x56);
}
// Apply patch.
@@ -93,12 +77,15 @@
uint32_t diff = target_offset - anchor_offset;
diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low".
- // LUI reg, offset_high / AUIPC reg, offset_high
- (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
- (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
- // instr reg(s), offset_low
- (*code)[literal_low_offset + 0] = static_cast<uint8_t>(diff >> 0);
- (*code)[literal_low_offset + 1] = static_cast<uint8_t>(diff >> 8);
+ if (high_patch) {
+ // lui reg, offset_high / auipc reg, offset_high
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
+ } else {
+ // instr reg(s), offset_low
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
+ }
}
void MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
diff --git a/compiler/linker/mips/relative_patcher_mips32r6_test.cc b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
index 63ad8a5..d1a75e2 100644
--- a/compiler/linker/mips/relative_patcher_mips32r6_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
@@ -26,7 +26,9 @@
protected:
static const uint8_t kUnpatchedPcRelativeRawCode[];
- static const uint32_t kLiteralOffset;
+ static const uint32_t kLiteralOffsetHigh;
+ static const uint32_t kLiteralOffsetLow1;
+ static const uint32_t kLiteralOffsetLow2;
static const uint32_t kAnchorOffset;
static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
@@ -44,9 +46,11 @@
const uint8_t Mips32r6RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
0x34, 0x12, 0x5E, 0xEE, // auipc s2, high(diff); placeholder = 0x1234
0x78, 0x56, 0x52, 0x26, // addiu s2, s2, low(diff); placeholder = 0x5678
+ 0x78, 0x56, 0x52, 0x8E, // lw s2, (low(diff))(s2) ; placeholder = 0x5678
};
-const uint32_t Mips32r6RelativePatcherTest::kLiteralOffset = 0; // At auipc (where
- // patching starts).
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetHigh = 0; // At auipc.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow1 = 4; // At addiu.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow2 = 8; // At lw.
const uint32_t Mips32r6RelativePatcherTest::kAnchorOffset = 0; // At auipc (where PC+0 points).
const ArrayRef<const uint8_t> Mips32r6RelativePatcherTest::kUnpatchedPcRelativeCode(
kUnpatchedPcRelativeRawCode);
@@ -60,11 +64,12 @@
ASSERT_TRUE(result.first);
uint32_t diff = target_offset - (result.second + kAnchorOffset);
- diff += (diff & 0x8000) << 1; // Account for sign extension in addiu.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in addiu/lw.
const uint8_t expected_code[] = {
static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x5E, 0xEE,
static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+ static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
};
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
@@ -75,7 +80,9 @@
string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
bss_begin_ = bss_begin;
LinkerPatch patches[] = {
- LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
}
@@ -84,7 +91,9 @@
constexpr uint32_t kStringIndex = 1u;
string_index_to_offset_map_.Put(kStringIndex, string_offset);
LinkerPatch patches[] = {
- LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
}
diff --git a/compiler/linker/mips/relative_patcher_mips_test.cc b/compiler/linker/mips/relative_patcher_mips_test.cc
index 49af7c6..2f7a075 100644
--- a/compiler/linker/mips/relative_patcher_mips_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips_test.cc
@@ -26,7 +26,9 @@
protected:
static const uint8_t kUnpatchedPcRelativeRawCode[];
- static const uint32_t kLiteralOffset;
+ static const uint32_t kLiteralOffsetHigh;
+ static const uint32_t kLiteralOffsetLow1;
+ static const uint32_t kLiteralOffsetLow2;
static const uint32_t kAnchorOffset;
static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
@@ -46,8 +48,11 @@
0x34, 0x12, 0x12, 0x3C, // lui s2, high(diff); placeholder = 0x1234
0x21, 0x90, 0x5F, 0x02, // addu s2, s2, ra
0x78, 0x56, 0x52, 0x26, // addiu s2, s2, low(diff); placeholder = 0x5678
+ 0x78, 0x56, 0x52, 0x8E, // lw s2, (low(diff))(s2) ; placeholder = 0x5678
};
-const uint32_t MipsRelativePatcherTest::kLiteralOffset = 4; // At lui (where patching starts).
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetHigh = 4; // At lui.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow1 = 12; // At addiu.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow2 = 16; // At lw.
const uint32_t MipsRelativePatcherTest::kAnchorOffset = 8; // At addu (where PC+0 points).
const ArrayRef<const uint8_t> MipsRelativePatcherTest::kUnpatchedPcRelativeCode(
kUnpatchedPcRelativeRawCode);
@@ -61,13 +66,14 @@
ASSERT_TRUE(result.first);
uint32_t diff = target_offset - (result.second + kAnchorOffset);
- diff += (diff & 0x8000) << 1; // Account for sign extension in addiu.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in addiu/lw.
const uint8_t expected_code[] = {
0x00, 0x00, 0x10, 0x04,
static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x12, 0x3C,
0x21, 0x90, 0x5F, 0x02,
static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+ static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
};
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
@@ -78,7 +84,9 @@
string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
bss_begin_ = bss_begin;
LinkerPatch patches[] = {
- LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
}
@@ -87,7 +95,9 @@
constexpr uint32_t kStringIndex = 1u;
string_index_to_offset_map_.Put(kStringIndex, string_offset);
LinkerPatch patches[] = {
- LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
}
diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc
index 3488d6d..d9f4758 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64.cc
@@ -36,38 +36,11 @@
return offset; // No thunks added; no limit on relative call distance.
}
-void Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code,
- uint32_t literal_offset,
- uint32_t patch_offset,
- uint32_t target_offset) {
- // Basic sanity checks.
- DCHECK_GE(code->size(), 8u);
- DCHECK_LE(literal_offset, code->size() - 8u);
- // auipc reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
- DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
- // jialc reg, offset_low
- DCHECK_EQ((*code)[literal_offset + 4], 0x78);
- DCHECK_EQ((*code)[literal_offset + 5], 0x56);
- DCHECK_EQ(((*code)[literal_offset + 6] & 0xE0), 0x00);
- DCHECK_EQ((*code)[literal_offset + 7], 0xF8);
-
- // Apply patch.
- uint32_t diff = target_offset - patch_offset;
- // Note that a combination of auipc with an instruction that adds a sign-extended
- // 16-bit immediate operand (e.g. jialc) provides a PC-relative range of
- // PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end
- // by 32KB.
- diff += (diff & 0x8000) << 1; // Account for sign extension in jialc.
-
- // auipc reg, offset_high
- (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
- (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
- // jialc reg, offset_low
- (*code)[literal_offset + 4] = static_cast<uint8_t>(diff >> 0);
- (*code)[literal_offset + 5] = static_cast<uint8_t>(diff >> 8);
+void Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+ uint32_t literal_offset ATTRIBUTE_UNUSED,
+ uint32_t patch_offset ATTRIBUTE_UNUSED,
+ uint32_t target_offset ATTRIBUTE_UNUSED) {
+ UNIMPLEMENTED(FATAL) << "PatchCall unimplemented on MIPS64";
}
void Mips64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
@@ -76,19 +49,18 @@
uint32_t target_offset) {
uint32_t anchor_literal_offset = patch.PcInsnOffset();
uint32_t literal_offset = patch.LiteralOffset();
+ bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
- // Basic sanity checks.
- DCHECK_GE(code->size(), 8u);
- DCHECK_LE(literal_offset, code->size() - 8u);
- DCHECK_EQ(literal_offset, anchor_literal_offset);
- // auipc reg, offset_high
- DCHECK_EQ((*code)[literal_offset + 0], 0x34);
- DCHECK_EQ((*code)[literal_offset + 1], 0x12);
- DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
- DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
- // instr reg(s), offset_low
- DCHECK_EQ((*code)[literal_offset + 4], 0x78);
- DCHECK_EQ((*code)[literal_offset + 5], 0x56);
+ // Perform basic sanity checks.
+ if (high_patch) {
+ // auipc reg, offset_high
+ DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
+ DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
+ } else {
+ // instr reg(s), offset_low
+ CHECK_EQ((*code)[literal_offset + 0], 0x78);
+ CHECK_EQ((*code)[literal_offset + 1], 0x56);
+ }
// Apply patch.
uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
@@ -97,14 +69,17 @@
// 16-bit immediate operand (e.g. ld) provides a PC-relative range of
// PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end
// by 32KB.
- diff += (diff & 0x8000) << 1; // Account for sign extension in instruction following auipc.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low".
- // auipc reg, offset_high
- (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
- (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
- // instr reg(s), offset_low
- (*code)[literal_offset + 4] = static_cast<uint8_t>(diff >> 0);
- (*code)[literal_offset + 5] = static_cast<uint8_t>(diff >> 8);
+ if (high_patch) {
+ // auipc reg, offset_high
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
+ } else {
+ // instr reg(s), offset_low
+ (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
+ (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
+ }
}
void Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
diff --git a/compiler/linker/mips64/relative_patcher_mips64_test.cc b/compiler/linker/mips64/relative_patcher_mips64_test.cc
index 9c9e24a..a5f494d 100644
--- a/compiler/linker/mips64/relative_patcher_mips64_test.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64_test.cc
@@ -27,10 +27,11 @@
protected:
static const uint8_t kUnpatchedPcRelativeRawCode[];
static const uint8_t kUnpatchedPcRelativeCallRawCode[];
- static const uint32_t kLiteralOffset;
+ static const uint32_t kLiteralOffsetHigh;
+ static const uint32_t kLiteralOffsetLow1;
+ static const uint32_t kLiteralOffsetLow2;
static const uint32_t kAnchorOffset;
static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
- static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCallCode;
uint32_t GetMethodOffset(uint32_t method_idx) {
auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
@@ -44,19 +45,16 @@
};
const uint8_t Mips64RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
- 0x34, 0x12, 0x5E, 0xEE, // auipc s2, high(diff); placeholder = 0x1234
+ 0x34, 0x12, 0x5E, 0xEE, // auipc s2, high(diff); placeholder = 0x1234
0x78, 0x56, 0x52, 0x66, // daddiu s2, s2, low(diff); placeholder = 0x5678
+ 0x78, 0x56, 0x52, 0x9E, // lwu s2, (low(diff))(s2) ; placeholder = 0x5678
};
-const uint8_t Mips64RelativePatcherTest::kUnpatchedPcRelativeCallRawCode[] = {
- 0x34, 0x12, 0x3E, 0xEC, // auipc at, high(diff); placeholder = 0x1234
- 0x78, 0x56, 0x01, 0xF8, // jialc at, low(diff); placeholder = 0x5678
-};
-const uint32_t Mips64RelativePatcherTest::kLiteralOffset = 0; // At auipc (where patching starts).
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetHigh = 0; // At auipc.
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetLow1 = 4; // At daddiu.
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetLow2 = 8; // At lwu.
const uint32_t Mips64RelativePatcherTest::kAnchorOffset = 0; // At auipc (where PC+0 points).
const ArrayRef<const uint8_t> Mips64RelativePatcherTest::kUnpatchedPcRelativeCode(
kUnpatchedPcRelativeRawCode);
-const ArrayRef<const uint8_t> Mips64RelativePatcherTest::kUnpatchedPcRelativeCallCode(
- kUnpatchedPcRelativeCallRawCode);
void Mips64RelativePatcherTest::CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches,
uint32_t target_offset) {
@@ -67,11 +65,12 @@
ASSERT_TRUE(result.first);
uint32_t diff = target_offset - (result.second + kAnchorOffset);
- diff += (diff & 0x8000) << 1; // Account for sign extension in instruction following auipc.
+ diff += (diff & 0x8000) << 1; // Account for sign extension in daddiu/lwu.
const uint8_t expected_code[] = {
static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x5E, 0xEE,
static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x66,
+ static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x9E,
};
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
}
@@ -82,7 +81,9 @@
string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
bss_begin_ = bss_begin;
LinkerPatch patches[] = {
- LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+ LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
};
CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
}
@@ -91,38 +92,5 @@
TestStringBssEntry(/* bss_begin */ 0x12345678, /* string_entry_offset */ 0x1234);
}
-TEST_F(Mips64RelativePatcherTest, CallOther) {
- LinkerPatch method1_patches[] = {
- LinkerPatch::RelativeCodePatch(kLiteralOffset, nullptr, 2u),
- };
- AddCompiledMethod(MethodRef(1u),
- kUnpatchedPcRelativeCallCode,
- ArrayRef<const LinkerPatch>(method1_patches));
- LinkerPatch method2_patches[] = {
- LinkerPatch::RelativeCodePatch(kLiteralOffset, nullptr, 1u),
- };
- AddCompiledMethod(MethodRef(2u),
- kUnpatchedPcRelativeCallCode,
- ArrayRef<const LinkerPatch>(method2_patches));
- Link();
-
- uint32_t method1_offset = GetMethodOffset(1u);
- uint32_t method2_offset = GetMethodOffset(2u);
- uint32_t diff_after = method2_offset - (method1_offset + kAnchorOffset /* PC adjustment */);
- diff_after += (diff_after & 0x8000) << 1; // Account for sign extension in jialc.
- static const uint8_t method1_expected_code[] = {
- static_cast<uint8_t>(diff_after >> 16), static_cast<uint8_t>(diff_after >> 24), 0x3E, 0xEC,
- static_cast<uint8_t>(diff_after), static_cast<uint8_t>(diff_after >> 8), 0x01, 0xF8,
- };
- EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code)));
- uint32_t diff_before = method1_offset - (method2_offset + kAnchorOffset /* PC adjustment */);
- diff_before += (diff_before & 0x8000) << 1; // Account for sign extension in jialc.
- static const uint8_t method2_expected_code[] = {
- static_cast<uint8_t>(diff_before >> 16), static_cast<uint8_t>(diff_before >> 24), 0x3E, 0xEC,
- static_cast<uint8_t>(diff_before), static_cast<uint8_t>(diff_before >> 8), 0x01, 0xF8,
- };
- EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code)));
-}
-
} // namespace linker
} // namespace art
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index b39d412..5e9148e 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -208,8 +208,13 @@
LoadClassSlowPathMIPS(HLoadClass* cls,
HInstruction* at,
uint32_t dex_pc,
- bool do_clinit)
- : SlowPathCodeMIPS(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+ bool do_clinit,
+ const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high = nullptr)
+ : SlowPathCodeMIPS(at),
+ cls_(cls),
+ dex_pc_(dex_pc),
+ do_clinit_(do_clinit),
+ bss_info_high_(bss_info_high) {
DCHECK(at->IsLoadClass() || at->IsClinitCheck());
}
@@ -217,8 +222,7 @@
LocationSummary* locations = instruction_->GetLocations();
Location out = locations->Out();
CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
- const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
- const bool r2_baker_or_no_read_barriers = !isR6 && (!kUseReadBarrier || kUseBakerReadBarrier);
+ const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
InvokeRuntimeCallingConvention calling_convention;
DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
const bool is_load_class_bss_entry =
@@ -228,7 +232,7 @@
// For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
Register entry_address = kNoRegister;
- if (is_load_class_bss_entry && r2_baker_or_no_read_barriers) {
+ if (is_load_class_bss_entry && baker_or_no_read_barriers) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
// In the unlucky case that `temp` is A0, we preserve the address in `out` across the
@@ -252,9 +256,18 @@
}
// For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
- if (is_load_class_bss_entry && r2_baker_or_no_read_barriers) {
+ if (is_load_class_bss_entry && baker_or_no_read_barriers) {
// The class entry address was preserved in `entry_address` thanks to kSaveEverything.
- __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(0), entry_address, 0);
+ DCHECK(bss_info_high_);
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, bss_info_high_);
+ bool reordering = __ SetReorder(false);
+ __ Bind(&info_low->label);
+ __ StoreToOffset(kStoreWord,
+ calling_convention.GetRegisterAt(0),
+ entry_address,
+ /* placeholder */ 0x5678);
+ __ SetReorder(reordering);
}
// Move the class to the desired location.
@@ -268,14 +281,17 @@
RestoreLiveRegisters(codegen, locations);
// For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
- if (is_load_class_bss_entry && !r2_baker_or_no_read_barriers) {
- // For non-Baker read barriers (or on R6), we need to re-calculate the address of
+ if (is_load_class_bss_entry && !baker_or_no_read_barriers) {
+ // For non-Baker read barriers we need to re-calculate the address of
// the class entry.
+ const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, info_high);
bool reordering = __ SetReorder(false);
- mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
+ mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base, info_low);
__ StoreToOffset(kStoreWord, out.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
__ SetReorder(reordering);
}
@@ -294,12 +310,17 @@
// Whether to initialize the class.
const bool do_clinit_;
+ // Pointer to the high half PC-relative patch info for HLoadClass/kBssEntry.
+ const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high_;
+
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
};
class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
public:
- explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
+ explicit LoadStringSlowPathMIPS(HLoadString* instruction,
+ const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high)
+ : SlowPathCodeMIPS(instruction), bss_info_high_(bss_info_high) {}
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
DCHECK(instruction_->IsLoadString());
@@ -310,15 +331,14 @@
const dex::StringIndex string_index = load->GetStringIndex();
Register out = locations->Out().AsRegister<Register>();
CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
- const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
- const bool r2_baker_or_no_read_barriers = !isR6 && (!kUseReadBarrier || kUseBakerReadBarrier);
+ const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
InvokeRuntimeCallingConvention calling_convention;
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, locations);
// For HLoadString/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
Register entry_address = kNoRegister;
- if (r2_baker_or_no_read_barriers) {
+ if (baker_or_no_read_barriers) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
// In the unlucky case that `temp` is A0, we preserve the address in `out` across the
@@ -335,9 +355,18 @@
CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
// Store the resolved string to the BSS entry.
- if (r2_baker_or_no_read_barriers) {
+ if (baker_or_no_read_barriers) {
// The string entry address was preserved in `entry_address` thanks to kSaveEverything.
- __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(0), entry_address, 0);
+ DCHECK(bss_info_high_);
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, bss_info_high_);
+ bool reordering = __ SetReorder(false);
+ __ Bind(&info_low->label);
+ __ StoreToOffset(kStoreWord,
+ calling_convention.GetRegisterAt(0),
+ entry_address,
+ /* placeholder */ 0x5678);
+ __ SetReorder(reordering);
}
Primitive::Type type = instruction_->GetType();
@@ -347,14 +376,17 @@
RestoreLiveRegisters(codegen, locations);
// Store the resolved string to the BSS entry.
- if (!r2_baker_or_no_read_barriers) {
- // For non-Baker read barriers (or on R6), we need to re-calculate the address of
+ if (!baker_or_no_read_barriers) {
+ // For non-Baker read barriers we need to re-calculate the address of
// the string entry.
+ const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, info_high);
bool reordering = __ SetReorder(false);
- mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
+ mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base, info_low);
__ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
__ SetReorder(reordering);
}
@@ -364,6 +396,9 @@
const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
private:
+ // Pointer to the high half PC-relative patch info.
+ const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high_;
+
DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
};
@@ -1584,14 +1619,15 @@
for (const PcRelativePatchInfo& info : infos) {
const DexFile& dex_file = info.target_dex_file;
size_t offset_or_index = info.offset_or_index;
- DCHECK(info.high_label.IsBound());
- uint32_t high_offset = __ GetLabelLocation(&info.high_label);
+ DCHECK(info.label.IsBound());
+ uint32_t literal_offset = __ GetLabelLocation(&info.label);
// On R2 we use HMipsComputeBaseMethodAddress and patch relative to
// the assembler's base label used for PC-relative addressing.
- uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
- ? __ GetLabelLocation(&info.pc_rel_label)
+ const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
+ uint32_t pc_rel_offset = info_high.pc_rel_label.IsBound()
+ ? __ GetLabelLocation(&info_high.pc_rel_label)
: __ GetPcRelBaseLabelLocation();
- linker_patches->push_back(Factory(high_offset, &dex_file, pc_rel_offset, offset_or_index));
+ linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
}
}
@@ -1625,37 +1661,50 @@
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeMethodPatch(
- MethodReference target_method) {
+ MethodReference target_method,
+ const PcRelativePatchInfo* info_high) {
return NewPcRelativePatch(*target_method.dex_file,
target_method.dex_method_index,
+ info_high,
&pc_relative_method_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
- MethodReference target_method) {
+ MethodReference target_method,
+ const PcRelativePatchInfo* info_high) {
return NewPcRelativePatch(*target_method.dex_file,
target_method.dex_method_index,
+ info_high,
&method_bss_entry_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
- const DexFile& dex_file, dex::TypeIndex type_index) {
- return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
+ const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
- const DexFile& dex_file, dex::TypeIndex type_index) {
- return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
+ const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
- const DexFile& dex_file, dex::StringIndex string_index) {
- return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
+ const DexFile& dex_file,
+ dex::StringIndex string_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
- const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
- patches->emplace_back(dex_file, offset_or_index);
+ const DexFile& dex_file,
+ uint32_t offset_or_index,
+ const PcRelativePatchInfo* info_high,
+ ArenaDeque<PcRelativePatchInfo>* patches) {
+ patches->emplace_back(dex_file, offset_or_index, info_high);
return &patches->back();
}
@@ -1669,14 +1718,16 @@
return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
}
-void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
+void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
Register out,
- Register base) {
+ Register base,
+ PcRelativePatchInfo* info_low) {
+ DCHECK(!info_high->patch_info_high);
DCHECK_NE(out, base);
if (GetInstructionSetFeatures().IsR6()) {
DCHECK_EQ(base, ZERO);
- __ Bind(&info->high_label);
- __ Bind(&info->pc_rel_label);
+ __ Bind(&info_high->label);
+ __ Bind(&info_high->pc_rel_label);
// Add the high half of a 32-bit offset to PC.
__ Auipc(out, /* placeholder */ 0x1234);
} else {
@@ -1685,18 +1736,20 @@
// Generate a dummy PC-relative call to obtain PC.
__ Nal();
}
- __ Bind(&info->high_label);
+ __ Bind(&info_high->label);
__ Lui(out, /* placeholder */ 0x1234);
// If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
// the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
if (base == ZERO) {
- __ Bind(&info->pc_rel_label);
+ __ Bind(&info_high->pc_rel_label);
}
// Add the high half of a 32-bit offset to PC.
__ Addu(out, out, (base == ZERO) ? RA : base);
}
- // The immediately following instruction will add the sign-extended low half of the 32-bit
+ // A following instruction will add the sign-extended low half of the 32-bit
// offset to `out` (e.g. lw, jialc, addiu).
+ DCHECK_EQ(info_low->patch_info_high, info_high);
+ __ Bind(&info_low->label);
}
CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
@@ -7140,10 +7193,12 @@
break;
case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
DCHECK(GetCompilerOptions().IsBootImage());
- PcRelativePatchInfo* info = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+ PcRelativePatchInfo* info_high = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+ PcRelativePatchInfo* info_low =
+ NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
bool reordering = __ SetReorder(false);
Register temp_reg = temp.AsRegister<Register>();
- EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+ EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg, info_low);
__ Addiu(temp_reg, TMP, /* placeholder */ 0x5678);
__ SetReorder(reordering);
break;
@@ -7152,11 +7207,13 @@
__ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
break;
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
- PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+ PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
+ PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
+ MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
Register temp_reg = temp.AsRegister<Register>();
bool reordering = __ SetReorder(false);
- EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+ EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg, info_low);
__ Lw(temp_reg, TMP, /* placeholder */ 0x5678);
__ SetReorder(reordering);
break;
@@ -7286,11 +7343,8 @@
if (load_kind == HLoadClass::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the type resolution or initialization and marking to save everything we need.
- // Request a temp to hold the BSS entry location for the slow path on R2
- // (no benefit for R6).
- if (!isR6) {
- locations->AddTemp(Location::RequiresRegister());
- }
+ // Request a temp to hold the BSS entry location for the slow path.
+ locations->AddTemp(Location::RequiresRegister());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -7336,6 +7390,7 @@
? kWithoutReadBarrier
: kCompilerReadBarrierOption;
bool generate_null_check = false;
+ CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high = nullptr;
switch (load_kind) {
case HLoadClass::LoadKind::kReferrersClass: {
DCHECK(!cls->CanCallRuntime());
@@ -7351,10 +7406,15 @@
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
DCHECK(codegen_->GetCompilerOptions().IsBootImage());
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+ out,
+ base_or_current_method_reg,
+ info_low);
__ Addiu(out, out, /* placeholder */ 0x5678);
__ SetReorder(reordering);
break;
@@ -7370,24 +7430,18 @@
break;
}
case HLoadClass::LoadKind::kBssEntry: {
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
- codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+ bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
- if (isR6 || non_baker_read_barrier) {
- bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
- GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
- __ SetReorder(reordering);
- } else {
- // On R2 save the BSS entry address in a temporary register instead of
- // recalculating it in the slow path.
- Register temp = locations->GetTemp(0).AsRegister<Register>();
- bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, temp, base_or_current_method_reg);
- __ Addiu(temp, temp, /* placeholder */ 0x5678);
- __ SetReorder(reordering);
- GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
- }
+ Register temp = non_baker_read_barrier ? out : locations->GetTemp(0).AsRegister<Register>();
+ bool reordering = __ SetReorder(false);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high,
+ temp,
+ base_or_current_method_reg,
+ info_low);
+ GenerateGcRootFieldLoad(cls, out_loc, temp, /* placeholder */ 0x5678, read_barrier_option);
+ __ SetReorder(reordering);
generate_null_check = true;
break;
}
@@ -7411,7 +7465,7 @@
if (generate_null_check || cls->MustGenerateClinitCheck()) {
DCHECK(cls->CanCallRuntime());
SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
- cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+ cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck(), bss_info_high);
codegen_->AddSlowPath(slow_path);
if (generate_null_check) {
__ Beqz(out, slow_path->GetEntryLabel());
@@ -7476,11 +7530,8 @@
if (load_kind == HLoadString::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the pResolveString and marking to save everything we need.
- // Request a temp to hold the BSS entry location for the slow path on R2
- // (no benefit for R6).
- if (!isR6) {
- locations->AddTemp(Location::RequiresRegister());
- }
+ // Request a temp to hold the BSS entry location for the slow path.
+ locations->AddTemp(Location::RequiresRegister());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -7516,10 +7567,15 @@
switch (load_kind) {
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
DCHECK(codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+ out,
+ base_or_current_method_reg,
+ info_low);
__ Addiu(out, out, /* placeholder */ 0x5678);
__ SetReorder(reordering);
return; // No dex cache slow path.
@@ -7535,29 +7591,25 @@
}
case HLoadString::LoadKind::kBssEntry: {
DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
- if (isR6 || non_baker_read_barrier) {
- bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
- GenerateGcRootFieldLoad(load,
- out_loc,
- out,
- /* placeholder */ 0x5678,
- kCompilerReadBarrierOption);
- __ SetReorder(reordering);
- } else {
- // On R2 save the BSS entry address in a temporary register instead of
- // recalculating it in the slow path.
- Register temp = locations->GetTemp(0).AsRegister<Register>();
- bool reordering = __ SetReorder(false);
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, temp, base_or_current_method_reg);
- __ Addiu(temp, temp, /* placeholder */ 0x5678);
- __ SetReorder(reordering);
- GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
- }
- SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
+ Register temp = non_baker_read_barrier ? out : locations->GetTemp(0).AsRegister<Register>();
+ bool reordering = __ SetReorder(false);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+ temp,
+ base_or_current_method_reg,
+ info_low);
+ GenerateGcRootFieldLoad(load,
+ out_loc,
+ temp,
+ /* placeholder */ 0x5678,
+ kCompilerReadBarrierOption);
+ __ SetReorder(reordering);
+ SlowPathCodeMIPS* slow_path =
+ new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load, info_high);
codegen_->AddSlowPath(slow_path);
__ Beqz(out, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index e72e838d..6719ef3 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -568,31 +568,68 @@
// The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
// and boot image strings. The only difference is the interpretation of the offset_or_index.
+ // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
+ // two patches/infos. There can be more than two patches/infos if the instruction supplying
+ // the high half is shared with e.g. a slow path, while the low half is supplied by separate
+ // instructions, e.g.:
+ // lui r1, high // patch
+ // addu r1, r1, rbase
+ // lw r2, low(r1) // patch
+ // beqz r2, slow_path
+ // back:
+ // ...
+ // slow_path:
+ // ...
+ // sw r2, low(r1) // patch
+ // b back
struct PcRelativePatchInfo {
- PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
- : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
- PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
+ PcRelativePatchInfo(const DexFile& dex_file,
+ uint32_t off_or_idx,
+ const PcRelativePatchInfo* info_high)
+ : target_dex_file(dex_file),
+ offset_or_index(off_or_idx),
+ label(),
+ pc_rel_label(),
+ patch_info_high(info_high) { }
const DexFile& target_dex_file;
// Either the dex cache array element offset or the string/type index.
uint32_t offset_or_index;
- // Label for the instruction loading the most significant half of the offset that's added to PC
- // to form the base address (the least significant half is loaded with the instruction that
- // follows).
- MipsLabel high_label;
- // Label for the instruction corresponding to PC+0.
+ // Label for the instruction to patch.
+ MipsLabel label;
+ // Label for the instruction corresponding to PC+0. Not bound or used in low half patches.
+ // Not bound in high half patches on R2 when using HMipsComputeBaseMethodAddress.
+ // Bound in high half patches on R2 when using the NAL instruction instead of
+ // HMipsComputeBaseMethodAddress.
+ // Bound in high half patches on R6.
MipsLabel pc_rel_label;
+ // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
+ const PcRelativePatchInfo* patch_info_high;
+
+ private:
+ PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
+ DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
};
- PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
- PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
- PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
+ PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
- dex::StringIndex string_index);
+ dex::StringIndex string_index,
+ const PcRelativePatchInfo* info_high = nullptr);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
- void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, Register out, Register base);
+ void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+ Register out,
+ Register base,
+ PcRelativePatchInfo* info_low);
// The JitPatchInfo is used for JIT string and class loads.
struct JitPatchInfo {
@@ -627,6 +664,7 @@
Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
uint32_t offset_or_index,
+ const PcRelativePatchInfo* info_high,
ArenaDeque<PcRelativePatchInfo>* patches);
template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index e4f1cbd..5fb8755 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -164,19 +164,42 @@
LoadClassSlowPathMIPS64(HLoadClass* cls,
HInstruction* at,
uint32_t dex_pc,
- bool do_clinit)
- : SlowPathCodeMIPS64(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+ bool do_clinit,
+ const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high = nullptr)
+ : SlowPathCodeMIPS64(at),
+ cls_(cls),
+ dex_pc_(dex_pc),
+ do_clinit_(do_clinit),
+ bss_info_high_(bss_info_high) {
DCHECK(at->IsLoadClass() || at->IsClinitCheck());
}
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
+ Location out = locations->Out();
CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
-
+ const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
+ InvokeRuntimeCallingConvention calling_convention;
+ DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
+ const bool is_load_class_bss_entry =
+ (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, locations);
- InvokeRuntimeCallingConvention calling_convention;
+ // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
+ GpuRegister entry_address = kNoGpuRegister;
+ if (is_load_class_bss_entry && baker_or_no_read_barriers) {
+ GpuRegister temp = locations->GetTemp(0).AsRegister<GpuRegister>();
+ bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
+ // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
+ // kSaveEverything call.
+ entry_address = temp_is_a0 ? out.AsRegister<GpuRegister>() : temp;
+ DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
+ if (temp_is_a0) {
+ __ Move(entry_address, temp);
+ }
+ }
+
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
@@ -188,8 +211,20 @@
CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
}
+ // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
+ if (is_load_class_bss_entry && baker_or_no_read_barriers) {
+ // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
+ DCHECK(bss_info_high_);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, bss_info_high_);
+ __ Bind(&info_low->label);
+ __ StoreToOffset(kStoreWord,
+ calling_convention.GetRegisterAt(0),
+ entry_address,
+ /* placeholder */ 0x5678);
+ }
+
// Move the class to the desired location.
- Location out = locations->Out();
if (out.IsValid()) {
DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Primitive::Type type = instruction_->GetType();
@@ -197,16 +232,18 @@
Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
type);
}
-
RestoreLiveRegisters(codegen, locations);
- // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
- DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
- if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
- DCHECK(out.IsValid());
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+
+ // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
+ if (is_load_class_bss_entry && !baker_or_no_read_barriers) {
+ // For non-Baker read barriers we need to re-calculate the address of
+ // the class entry.
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
- mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
- __ Sw(out.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, info_high);
+ mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, info_low);
+ __ StoreToOffset(kStoreWord, out.AsRegister<GpuRegister>(), TMP, /* placeholder */ 0x5678);
}
__ Bc(GetExitLabel());
}
@@ -223,50 +260,94 @@
// Whether to initialize the class.
const bool do_clinit_;
+ // Pointer to the high half PC-relative patch info for HLoadClass/kBssEntry.
+ const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high_;
+
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS64);
};
class LoadStringSlowPathMIPS64 : public SlowPathCodeMIPS64 {
public:
- explicit LoadStringSlowPathMIPS64(HLoadString* instruction) : SlowPathCodeMIPS64(instruction) {}
+ explicit LoadStringSlowPathMIPS64(HLoadString* instruction,
+ const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high)
+ : SlowPathCodeMIPS64(instruction), bss_info_high_(bss_info_high) {}
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ DCHECK(instruction_->IsLoadString());
+ DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
LocationSummary* locations = instruction_->GetLocations();
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+ HLoadString* load = instruction_->AsLoadString();
+ const dex::StringIndex string_index = load->GetStringIndex();
+ GpuRegister out = locations->Out().AsRegister<GpuRegister>();
CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
-
+ const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
+ InvokeRuntimeCallingConvention calling_convention;
__ Bind(GetEntryLabel());
SaveLiveRegisters(codegen, locations);
- InvokeRuntimeCallingConvention calling_convention;
- HLoadString* load = instruction_->AsLoadString();
- const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
+ // For HLoadString/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
+ GpuRegister entry_address = kNoGpuRegister;
+ if (baker_or_no_read_barriers) {
+ GpuRegister temp = locations->GetTemp(0).AsRegister<GpuRegister>();
+ bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
+ // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
+ // kSaveEverything call.
+ entry_address = temp_is_a0 ? out : temp;
+ DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
+ if (temp_is_a0) {
+ __ Move(entry_address, temp);
+ }
+ }
+
__ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
mips64_codegen->InvokeRuntime(kQuickResolveString,
instruction_,
instruction_->GetDexPc(),
this);
CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
+
+ // Store the resolved string to the BSS entry.
+ if (baker_or_no_read_barriers) {
+ // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
+ DCHECK(bss_info_high_);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(),
+ string_index,
+ bss_info_high_);
+ __ Bind(&info_low->label);
+ __ StoreToOffset(kStoreWord,
+ calling_convention.GetRegisterAt(0),
+ entry_address,
+ /* placeholder */ 0x5678);
+ }
+
Primitive::Type type = instruction_->GetType();
mips64_codegen->MoveLocation(locations->Out(),
Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
type);
-
RestoreLiveRegisters(codegen, locations);
- // Store the resolved String to the BSS entry.
- GpuRegister out = locations->Out().AsRegister<GpuRegister>();
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
- mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
- mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
- __ Sw(out, AT, /* placeholder */ 0x5678);
-
+ // Store the resolved string to the BSS entry.
+ if (!baker_or_no_read_barriers) {
+ // For non-Baker read barriers we need to re-calculate the address of
+ // the string entry.
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
+ mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, info_high);
+ mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, info_low);
+ __ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
+ }
__ Bc(GetExitLabel());
}
const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS64"; }
private:
+ // Pointer to the high half PC-relative patch info.
+ const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high_;
+
DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS64);
};
@@ -1431,9 +1512,11 @@
for (const PcRelativePatchInfo& info : infos) {
const DexFile& dex_file = info.target_dex_file;
size_t offset_or_index = info.offset_or_index;
- DCHECK(info.pc_rel_label.IsBound());
- uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label);
- linker_patches->push_back(Factory(pc_rel_offset, &dex_file, pc_rel_offset, offset_or_index));
+ DCHECK(info.label.IsBound());
+ uint32_t literal_offset = __ GetLabelLocation(&info.label);
+ const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
+ uint32_t pc_rel_offset = __ GetLabelLocation(&info_high.label);
+ linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
}
}
@@ -1467,37 +1550,50 @@
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeMethodPatch(
- MethodReference target_method) {
+ MethodReference target_method,
+ const PcRelativePatchInfo* info_high) {
return NewPcRelativePatch(*target_method.dex_file,
target_method.dex_method_index,
+ info_high,
&pc_relative_method_patches_);
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewMethodBssEntryPatch(
- MethodReference target_method) {
+ MethodReference target_method,
+ const PcRelativePatchInfo* info_high) {
return NewPcRelativePatch(*target_method.dex_file,
target_method.dex_method_index,
+ info_high,
&method_bss_entry_patches_);
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeTypePatch(
- const DexFile& dex_file, dex::TypeIndex type_index) {
- return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
+ const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewTypeBssEntryPatch(
- const DexFile& dex_file, dex::TypeIndex type_index) {
- return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
+ const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeStringPatch(
- const DexFile& dex_file, dex::StringIndex string_index) {
- return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
+ const DexFile& dex_file,
+ dex::StringIndex string_index,
+ const PcRelativePatchInfo* info_high) {
+ return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
}
CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch(
- const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
- patches->emplace_back(dex_file, offset_or_index);
+ const DexFile& dex_file,
+ uint32_t offset_or_index,
+ const PcRelativePatchInfo* info_high,
+ ArenaDeque<PcRelativePatchInfo>* patches) {
+ patches->emplace_back(dex_file, offset_or_index, info_high);
return &patches->back();
}
@@ -1517,13 +1613,17 @@
return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
}
-void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
- GpuRegister out) {
- __ Bind(&info->pc_rel_label);
+void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+ GpuRegister out,
+ PcRelativePatchInfo* info_low) {
+ DCHECK(!info_high->patch_info_high);
+ __ Bind(&info_high->label);
// Add the high half of a 32-bit offset to PC.
__ Auipc(out, /* placeholder */ 0x1234);
- // The immediately following instruction will add the sign-extended low half of the 32-bit
+ // A following instruction will add the sign-extended low half of the 32-bit
// offset to `out` (e.g. ld, jialc, daddiu).
+ DCHECK_EQ(info_low->patch_info_high, info_high);
+ __ Bind(&info_low->label);
}
Literal* CodeGeneratorMIPS64::DeduplicateJitStringLiteral(const DexFile& dex_file,
@@ -4940,9 +5040,11 @@
break;
case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
DCHECK(GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
NewPcRelativeMethodPatch(invoke->GetTargetMethod());
- EmitPcRelativeAddressPlaceholderHigh(info, AT);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
+ EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
__ Daddiu(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
break;
}
@@ -4952,9 +5054,11 @@
DeduplicateUint64Literal(invoke->GetMethodAddress()));
break;
case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
- PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+ PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
- EmitPcRelativeAddressPlaceholderHigh(info, AT);
+ PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
+ MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
+ EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
__ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
break;
}
@@ -5071,12 +5175,14 @@
if (load_kind == HLoadClass::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the type resolution or initialization and marking to save everything we need.
+ // Request a temp to hold the BSS entry location for the slow path.
+ locations->AddTemp(Location::RequiresRegister());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetCustomSlowPathCallerSaves(caller_saves);
} else {
- // For non-Baker read barrier we have a temp-clobbering call.
+ // For non-Baker read barriers we have a temp-clobbering call.
}
}
}
@@ -5104,6 +5210,7 @@
? kWithoutReadBarrier
: kCompilerReadBarrierOption;
bool generate_null_check = false;
+ CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high = nullptr;
switch (load_kind) {
case HLoadClass::LoadKind::kReferrersClass:
DCHECK(!cls->CanCallRuntime());
@@ -5118,9 +5225,11 @@
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
DCHECK(codegen_->GetCompilerOptions().IsBootImage());
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
__ Daddiu(out, AT, /* placeholder */ 0x5678);
break;
}
@@ -5135,10 +5244,15 @@
break;
}
case HLoadClass::LoadKind::kBssEntry: {
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
- codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
- GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
+ bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
+ constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
+ GpuRegister temp = non_baker_read_barrier
+ ? out
+ : locations->GetTemp(0).AsRegister<GpuRegister>();
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high, temp, info_low);
+ GenerateGcRootFieldLoad(cls, out_loc, temp, /* placeholder */ 0x5678, read_barrier_option);
generate_null_check = true;
break;
}
@@ -5159,7 +5273,7 @@
if (generate_null_check || cls->MustGenerateClinitCheck()) {
DCHECK(cls->CanCallRuntime());
SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS64(
- cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+ cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck(), bss_info_high);
codegen_->AddSlowPath(slow_path);
if (generate_null_check) {
__ Beqzc(out, slow_path->GetEntryLabel());
@@ -5207,12 +5321,14 @@
if (load_kind == HLoadString::LoadKind::kBssEntry) {
if (!kUseReadBarrier || kUseBakerReadBarrier) {
// Rely on the pResolveString and marking to save everything we need.
+ // Request a temp to hold the BSS entry location for the slow path.
+ locations->AddTemp(Location::RequiresRegister());
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetCustomSlowPathCallerSaves(caller_saves);
} else {
- // For non-Baker read barrier we have a temp-clobbering call.
+ // For non-Baker read barriers we have a temp-clobbering call.
}
}
}
@@ -5229,9 +5345,11 @@
switch (load_kind) {
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
DCHECK(codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
__ Daddiu(out, AT, /* placeholder */ 0x5678);
return; // No dex cache slow path.
}
@@ -5246,15 +5364,22 @@
}
case HLoadString::LoadKind::kBssEntry: {
DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
- codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+ constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
+ GpuRegister temp = non_baker_read_barrier
+ ? out
+ : locations->GetTemp(0).AsRegister<GpuRegister>();
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, temp, info_low);
GenerateGcRootFieldLoad(load,
out_loc,
- out,
+ temp,
/* placeholder */ 0x5678,
kCompilerReadBarrierOption);
- SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
+ SlowPathCodeMIPS64* slow_path =
+ new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load, info_high);
codegen_->AddSlowPath(slow_path);
__ Beqzc(out, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 6260c73..b620973 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -538,29 +538,59 @@
// The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays,
// boot image strings and method calls. The only difference is the interpretation of
// the offset_or_index.
+ // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
+ // two patches/infos. There can be more than two patches/infos if the instruction supplying
+ // the high half is shared with e.g. a slow path, while the low half is supplied by separate
+ // instructions, e.g.:
+ // auipc r1, high // patch
+ // lwu r2, low(r1) // patch
+ // beqzc r2, slow_path
+ // back:
+ // ...
+ // slow_path:
+ // ...
+ // sw r2, low(r1) // patch
+ // bc back
struct PcRelativePatchInfo {
- PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
- : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
- PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
+ PcRelativePatchInfo(const DexFile& dex_file,
+ uint32_t off_or_idx,
+ const PcRelativePatchInfo* info_high)
+ : target_dex_file(dex_file),
+ offset_or_index(off_or_idx),
+ label(),
+ patch_info_high(info_high) { }
const DexFile& target_dex_file;
// Either the dex cache array element offset or the string/type/method index.
uint32_t offset_or_index;
- // Label for the auipc instruction.
- Mips64Label pc_rel_label;
+ // Label for the instruction to patch.
+ Mips64Label label;
+ // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
+ const PcRelativePatchInfo* patch_info_high;
+
+ private:
+ PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
+ DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
};
- PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
- PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
- PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
+ PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high = nullptr);
+ PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ const PcRelativePatchInfo* info_high = nullptr);
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
- dex::StringIndex string_index);
- PcRelativePatchInfo* NewPcRelativeCallPatch(const DexFile& dex_file,
- uint32_t method_index);
+ dex::StringIndex string_index,
+ const PcRelativePatchInfo* info_high = nullptr);
Literal* DeduplicateBootImageAddressLiteral(uint64_t address);
- void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, GpuRegister out);
+ void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+ GpuRegister out,
+ PcRelativePatchInfo* info_low);
void PatchJitRootUse(uint8_t* code,
const uint8_t* roots_data,
@@ -588,6 +618,7 @@
PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
uint32_t offset_or_index,
+ const PcRelativePatchInfo* info_high,
ArenaDeque<PcRelativePatchInfo>* patches);
template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>