From df0085ada5d4cf322eb782b0aef818be55f79873 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 20 Jan 2015 16:54:29 -0700 Subject: [PATCH] use unconditional branch to stack overflow thunk on ARM64 On ARM64, conditional branches to immediate offsets can span no more than 2^19 instructions. In the case of the stack overflow check, which wants to do a conditional branch from every non-leaf method to a handler, this can be a problem, especially when compiled code grows large as with a bootimage=true build against the OpenJDK class library. Therefore, we use an unconditional branch to reach the handler on this platform. --- src/codegen/target/arm/assembler.cpp | 2 +- src/codegen/target/arm/fixup.cpp | 23 ++++++++++++----------- src/codegen/target/arm/operations64.cpp | 11 ++++++++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/codegen/target/arm/assembler.cpp b/src/codegen/target/arm/assembler.cpp index 3130662073..5181ad7c4d 100644 --- a/src/codegen/target/arm/assembler.cpp +++ b/src/codegen/target/arm/assembler.cpp @@ -95,7 +95,7 @@ void nextFrame(ArchitectureContext* con, if ((*start >> 20) == (TargetBytesPerWord == 8 ? 0xf94 : 0xe59)) { // skip stack overflow check - start += 3; + start += TargetBytesPerWord == 8 ? 4 : 3; } if (instruction <= start) { diff --git a/src/codegen/target/arm/fixup.cpp b/src/codegen/target/arm/fixup.cpp index 3117688b15..ebe1b7258e 100644 --- a/src/codegen/target/arm/fixup.cpp +++ b/src/codegen/target/arm/fixup.cpp @@ -102,22 +102,23 @@ void* updateOffset(vm::System* s, uint8_t* instruction, int64_t value) int32_t v; int32_t mask; if (vm::TargetBytesPerWord == 8) { - if ((*p >> 24) == 0x54) { - // conditional branch - v = ((reinterpret_cast(value) - instruction) >> 2) << 5; - mask = 0xFFFFE0; - } else { - // unconditional branch - v = (reinterpret_cast(value) - instruction) >> 2; - mask = 0x3FFFFFF; - } + if ((*p >> 24) == 0x54) { + // conditional branch + v = ((reinterpret_cast(value) - instruction) >> 2) << 5; + mask = 0xFFFFE0; + expect(s, bounded(5, 8, v)); + } else { + // unconditional branch + v = (reinterpret_cast(value) - instruction) >> 2; + mask = 0x3FFFFFF; + expect(s, bounded(0, 6, v)); + } } else { v = (reinterpret_cast(value) - (instruction + 8)) >> 2; mask = 0xFFFFFF; + expect(s, bounded(0, 8, v)); } - expect(s, bounded(0, 8, v)); - *p = (v & mask) | ((~mask) & *p); return instruction + InstructionSize; diff --git a/src/codegen/target/arm/operations64.cpp b/src/codegen/target/arm/operations64.cpp index e0c4a69ed6..a7fb2c80f1 100644 --- a/src/codegen/target/arm/operations64.cpp +++ b/src/codegen/target/arm/operations64.cpp @@ -1483,12 +1483,17 @@ void branchRM(Context* c, assertT(c, size <= vm::TargetBytesPerWord); if (a->low.index() == 31) { - // stack overflow checks need to compare to the stack pointer, but + // Stack overflow checks need to compare to the stack pointer, but // we can only encode that in the opposite operand order we're - // given, so we need to reverse everything: + // given, so we need to reverse everything. Also, we can't do a + // conditional jump further than 2^19 instructions away, which can + // cause trouble with large code, so we branch past an + // unconditional branch which can jump further, which reverses the + // logic again. Confused? Good. assertT(c, op == lir::JumpIfGreaterOrEqual); compareMR(c, size, b, size, a); - branch(c, lir::JumpIfLess, target); + append(c, bge(8)); + jumpC(c, vm::TargetBytesPerWord, target); } else { compareRM(c, size, a, size, b); branch(c, op, target);