diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-03-19 22:58:23 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-03-19 22:58:24 +0000 |
commit | 66e4c3e96dccdec7423d673ad6bbf7821a776651 (patch) | |
tree | fea99ef4dea02ccc16474c1b69a2fc1f3b3c2ce1 /compiler/dex | |
parent | 4af7b576e1618a8e31c9429c643e98932aea1d42 (diff) | |
parent | 0d507d1e0441e6bd6f3affca3a60774ea920f317 (diff) | |
download | art-66e4c3e96dccdec7423d673ad6bbf7821a776651.zip art-66e4c3e96dccdec7423d673ad6bbf7821a776651.tar.gz art-66e4c3e96dccdec7423d673ad6bbf7821a776651.tar.bz2 |
Merge "Optimize stack overflow handling."
Diffstat (limited to 'compiler/dex')
-rw-r--r-- | compiler/dex/compiler_enums.h | 1 | ||||
-rw-r--r-- | compiler/dex/quick/arm/call_arm.cc | 51 | ||||
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 30 | ||||
-rw-r--r-- | compiler/dex/quick/mips/call_mips.cc | 30 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 33 |
5 files changed, 100 insertions, 45 deletions
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 147e840..718468f 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -328,7 +328,6 @@ enum ThrowKind { kThrowArrayBounds, kThrowConstantArrayBounds, kThrowNoSuchMethod, - kThrowStackOverflow, }; enum DividePattern { diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index bba3d40..94f0ca4 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -358,23 +358,60 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { */ NewLIR1(kThumb2VPushCS, num_fp_spills_); } + + // TODO: 64 bit will be different code. + const int frame_size_without_spills = frame_size_ - spill_count * 4; if (!skip_overflow_check) { if (Runtime::Current()->ExplicitStackOverflowChecks()) { - OpRegRegImm(kOpSub, rARM_LR, rARM_SP, frame_size_ - (spill_count * 4)); - GenRegRegCheck(kCondUlt, rARM_LR, r12, kThrowStackOverflow); - OpRegCopy(rARM_SP, rARM_LR); // Establish stack + class StackOverflowSlowPath : public LIRSlowPath { + public: + StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace) + : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, nullptr), restore_lr_(restore_lr), + sp_displace_(sp_displace) { + } + void Compile() OVERRIDE { + m2l_->ResetRegPool(); + m2l_->ResetDefTracking(); + GenerateTargetLabel(); + if (restore_lr_) { + m2l_->LoadWordDisp(kArmRegSP, sp_displace_ - 4, kArmRegLR); + } + m2l_->OpRegImm(kOpAdd, kArmRegSP, sp_displace_); + m2l_->ClobberCallerSave(); + ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow); + // Load the entrypoint directly into the pc instead of doing a load + branch. Assumes + // codegen and target are in thumb2 mode. + m2l_->LoadWordDisp(rARM_SELF, func_offset.Int32Value(), rARM_PC); + } + + private: + const bool restore_lr_; + const size_t sp_displace_; + }; + if (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes) { + OpRegRegImm(kOpSub, rARM_LR, rARM_SP, frame_size_without_spills); + LIR* branch = OpCmpBranch(kCondUlt, rARM_LR, r12, nullptr); + // Need to restore LR since we used it as a temp. + AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, true, + frame_size_without_spills)); + OpRegCopy(rARM_SP, rARM_LR); // Establish stack + } else { + // If the frame is small enough we are guaranteed to have enough space that remains to + // handle signals on the user stack. + OpRegRegImm(kOpSub, rARM_SP, rARM_SP, frame_size_without_spills); + LIR* branch = OpCmpBranch(kCondUlt, rARM_SP, r12, nullptr); + AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_)); + } } else { // Implicit stack overflow check. // Generate a load from [sp, #-framesize]. If this is in the stack // redzone we will get a segmentation fault. - uint32_t full_frame_size = frame_size_ - (spill_count * 4); - - OpRegImm(kOpSub, rARM_SP, full_frame_size); + OpRegImm(kOpSub, rARM_SP, frame_size_without_spills); LoadWordDisp(rARM_SP, 0, rARM_LR); MarkPossibleStackOverflowException(); } } else { - OpRegImm(kOpSub, rARM_SP, frame_size_ - (spill_count * 4)); + OpRegImm(kOpSub, rARM_SP, frame_size_without_spills); } FlushIns(ArgLocs, rl_method); diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 71cc0d9..8c3a11f 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -629,8 +629,6 @@ void Mir2Lir::HandleThrowLaunchPads() { int v1 = lab->operands[2]; int v2 = lab->operands[3]; const bool target_x86 = cu_->instruction_set == kX86; - const bool target_arm = cu_->instruction_set == kArm || cu_->instruction_set == kThumb2; - const bool target_mips = cu_->instruction_set == kMips; switch (lab->operands[0]) { case kThrowNullPointer: func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNullPointer); @@ -688,34 +686,6 @@ void Mir2Lir::HandleThrowLaunchPads() { func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNoSuchMethod); break; - case kThrowStackOverflow: { - func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow); - // Restore stack alignment - int r_tgt = 0; - const int spill_size = (num_core_spills_ + num_fp_spills_) * 4; - if (target_x86) { - // - 4 to leave link register on stack. - OpRegImm(kOpAdd, TargetReg(kSp), frame_size_ - 4); - ClobberCallerSave(); - } else if (target_arm) { - r_tgt = r12; - LoadWordDisp(TargetReg(kSp), spill_size - 4, TargetReg(kLr)); - OpRegImm(kOpAdd, TargetReg(kSp), spill_size); - ClobberCallerSave(); - LoadWordDisp(rARM_SELF, func_offset.Int32Value(), r_tgt); - } else { - DCHECK(target_mips); - DCHECK_EQ(num_fp_spills_, 0); // FP spills currently don't happen on mips. - // LR is offset 0 since we push in reverse order. - LoadWordDisp(TargetReg(kSp), 0, TargetReg(kLr)); - OpRegImm(kOpAdd, TargetReg(kSp), spill_size); - ClobberCallerSave(); - r_tgt = CallHelperSetup(func_offset); // Doesn't clobber LR. - DCHECK_NE(r_tgt, TargetReg(kLr)); - } - CallHelper(r_tgt, func_offset, false /* MarkSafepointPC */, false /* UseLink */); - continue; - } default: LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0]; } diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index 234299e..95fd6e7 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -317,12 +317,36 @@ void MipsMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) SpillCoreRegs(); /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ DCHECK_EQ(num_fp_spills_, 0); + const int frame_sub = frame_size_ - spill_count * 4; if (!skip_overflow_check) { - OpRegRegImm(kOpSub, new_sp, rMIPS_SP, frame_size_ - (spill_count * 4)); - GenRegRegCheck(kCondUlt, new_sp, check_reg, kThrowStackOverflow); + class StackOverflowSlowPath : public LIRSlowPath { + public: + StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace) + : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, nullptr), sp_displace_(sp_displace) { + } + void Compile() OVERRIDE { + m2l_->ResetRegPool(); + m2l_->ResetDefTracking(); + GenerateTargetLabel(); + // LR is offset 0 since we push in reverse order. + m2l_->LoadWordDisp(kMipsRegSP, 0, kMipsRegLR); + m2l_->OpRegImm(kOpAdd, kMipsRegSP, sp_displace_); + m2l_->ClobberCallerSave(); + ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow); + int r_tgt = m2l_->CallHelperSetup(func_offset); // Doesn't clobber LR. + m2l_->CallHelper(r_tgt, func_offset, false /* MarkSafepointPC */, false /* UseLink */); + } + + private: + const size_t sp_displace_; + }; + OpRegRegImm(kOpSub, new_sp, rMIPS_SP, frame_sub); + LIR* branch = OpCmpBranch(kCondUlt, new_sp, check_reg, nullptr); + AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, spill_count * 4)); + // TODO: avoid copy for small frame sizes. OpRegCopy(rMIPS_SP, new_sp); // Establish stack } else { - OpRegImm(kOpSub, rMIPS_SP, frame_size_ - (spill_count * 4)); + OpRegImm(kOpSub, rMIPS_SP, frame_sub); } FlushIns(ArgLocs, rl_method); diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index 72fc922..68e2b6d 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -213,12 +213,37 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */ DCHECK_EQ(num_fp_spills_, 0); if (!skip_overflow_check) { + class StackOverflowSlowPath : public LIRSlowPath { + public: + StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace) + : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, nullptr), sp_displace_(sp_displace) { + } + void Compile() OVERRIDE { + m2l_->ResetRegPool(); + m2l_->ResetDefTracking(); + GenerateTargetLabel(); + m2l_->OpRegImm(kOpAdd, kX86RegSP, sp_displace_); + m2l_->ClobberCallerSave(); + ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow); + // Assumes codegen and target are in thumb2 mode. + m2l_->CallHelper(0, func_offset, false /* MarkSafepointPC */, false /* UseLink */); + } + + private: + const size_t sp_displace_; + }; + // TODO: for large frames we should do something like: + // spill ebp + // lea ebp, [esp + frame_size] + // cmp ebp, fs:[stack_end_] + // jcc stack_overflow_exception + // mov esp, ebp + // in case a signal comes in that's not using an alternate signal stack and the large frame may + // have moved us outside of the reserved area at the end of the stack. // cmp rX86_SP, fs:[stack_end_]; jcc throw_launchpad - LIR* tgt = RawLIR(0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0); OpRegThreadMem(kOpCmp, rX86_SP, Thread::StackEndOffset()); - OpCondBranch(kCondUlt, tgt); - // Remember branch target - will process later - throw_launchpads_.Insert(tgt); + LIR* branch = OpCondBranch(kCondUlt, nullptr); + AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, frame_size_ - 4)); } FlushIns(ArgLocs, rl_method); |