diff --git a/hphp/runtime/vm/jit/irgen-control.cpp b/hphp/runtime/vm/jit/irgen-control.cpp index b185429a0f27ef..376fc3383b33cb 100644 --- a/hphp/runtime/vm/jit/irgen-control.cpp +++ b/hphp/runtime/vm/jit/irgen-control.cpp @@ -296,6 +296,54 @@ void emitSelect(IRGS& env) { ////////////////////////////////////////////////////////////////////// +void emitHandleException(IRGS& env, EndCatchData::CatchMode mode, SSATmp* exc, + Optional vmspOffset) { + // Stublogues lack proper frames and need special configuration. + if (env.irb->fs().stublogue()) { + assertx(!isInlining(env)); + assertx(mode == EndCatchData::CatchMode::UnwindOnly); + auto const data = EndCatchData { + spOffBCFromIRSP(env), + EndCatchData::CatchMode::UnwindOnly, + EndCatchData::FrameMode::Stublogue, + EndCatchData::Teardown::NA, + std::nullopt + }; + gen(env, EndCatch, data, fp(env), sp(env)); + return; + } + + // Teardown::None can't be used without an empty stack. + assertx(IMPLIES(mode == EndCatchData::CatchMode::LocalsDecRefd, + spOffBCFromStackBase(env) == spOffEmpty(env))); + + // If we are unwinding from an inlined function, try a special logic that + // may eliminate the need to spill the current frame. + if (isInlining(env)) { + if (endCatchFromInlined(env, mode, exc)) return; + } + + if (spillInlinedFrames(env)) { + gen(env, StVMFP, fp(env)); + gen(env, StVMPC, cns(env, uintptr_t(curSrcKey(env).pc()))); + gen(env, StVMReturnAddr, cns(env, 0)); + } + + auto const teardown = mode == EndCatchData::CatchMode::LocalsDecRefd + ? EndCatchData::Teardown::None + : EndCatchData::Teardown::Full; + auto const data = EndCatchData { + spOffBCFromIRSP(env), + mode, + EndCatchData::FrameMode::Phplogue, + teardown, + vmspOffset + }; + gen(env, EndCatch, data, fp(env), sp(env)); +} + +////////////////////////////////////////////////////////////////////// + void emitThrow(IRGS& env) { auto const stackEmpty = spOffBCFromStackBase(env) == spOffEmpty(env) + 1; auto const offset = findCatchHandler(curFunc(env), bcOff(env)); diff --git a/hphp/runtime/vm/jit/irgen-control.h b/hphp/runtime/vm/jit/irgen-control.h index e3d5c841c665a9..6ccb3004f4c39b 100644 --- a/hphp/runtime/vm/jit/irgen-control.h +++ b/hphp/runtime/vm/jit/irgen-control.h @@ -17,6 +17,8 @@ #include "hphp/runtime/vm/hhbc.h" #include "hphp/runtime/vm/srckey.h" +#include "hphp/runtime/vm/jit/extra-data.h" +#include "hphp/runtime/vm/jit/ssa-tmp.h" namespace HPHP::jit { @@ -47,6 +49,16 @@ void jmpImpl(IRGS&, Offset); void jmpImpl(IRGS&, SrcKey); void implCondJmp(IRGS&, Offset taken, bool negate, SSATmp*); +/* + * Route exception `exc' to the appropriate handler. C++ exceptions are + * represented by TNullptr and must be ultimately handled by EndCatch, which + * gives control back to the unwinder. Otherwise `exc' will contain an object + * implementing the Throwable interface. Hack exceptions might be routed + * directly to the appropriate handlers. + */ +void emitHandleException(IRGS& env, EndCatchData::CatchMode mode, SSATmp* exc, + Optional vmspOffset); + ////////////////////////////////////////////////////////////////////// }} diff --git a/hphp/runtime/vm/jit/irgen-inlining.cpp b/hphp/runtime/vm/jit/irgen-inlining.cpp index bb0b0253082627..2a18e92c9e14d7 100644 --- a/hphp/runtime/vm/jit/irgen-inlining.cpp +++ b/hphp/runtime/vm/jit/irgen-inlining.cpp @@ -593,28 +593,9 @@ void implEndCatchBlock(IRGS& env, const RegionDesc& calleeRegion) { auto const inlineFrame = implInlineReturn(env); SCOPE_EXIT { pushInlineFrame(env, inlineFrame); }; - // If the caller is inlined as well, try to use shared EndCatch of its caller. - if (isInlining(env)) { - if (endCatchFromInlined(env, EndCatchData::CatchMode::UnwindOnly, exc)) { - return; - } - - if (spillInlinedFrames(env)) { - gen(env, StVMFP, fp(env)); - gen(env, StVMPC, cns(env, uintptr_t(curSrcKey(env).pc()))); - gen(env, StVMReturnAddr, cns(env, 0)); - } - } - - auto const data = EndCatchData { - spOffBCFromIRSP(env), - EndCatchData::CatchMode::UnwindOnly, - EndCatchData::FrameMode::Phplogue, - EndCatchData::Teardown::Full, - // vmspOffset is unknown at this point as there can be multiple BeginCatches - std::nullopt - }; - gen(env, EndCatch, data, fp(env), sp(env)); + // vmspOffset is unknown at this point due to multiple BeginCatches + emitHandleException( + env, EndCatchData::CatchMode::UnwindOnly, exc, std::nullopt); } //////////////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/vm/jit/irgen-internal.h b/hphp/runtime/vm/jit/irgen-internal.h index 741f7f4538d442..ff8b8486fd5912 100644 --- a/hphp/runtime/vm/jit/irgen-internal.h +++ b/hphp/runtime/vm/jit/irgen-internal.h @@ -26,7 +26,7 @@ #include "hphp/runtime/vm/jit/block.h" #include "hphp/runtime/vm/jit/decref-profile.h" #include "hphp/runtime/vm/jit/guard-constraint.h" -#include "hphp/runtime/vm/jit/irgen-inlining.h" +#include "hphp/runtime/vm/jit/irgen-control.h" #include "hphp/runtime/vm/jit/punt.h" #include "hphp/runtime/vm/jit/simplify.h" #include "hphp/runtime/vm/jit/ssa-tmp.h" @@ -869,51 +869,12 @@ Block* makeCatchBlock( auto const ty = Type::SubObj(SystemLib::getThrowableClass()) | TNullptr; auto const exc = gen(env, BeginCatch, ty); - body(); - - // Stublogues lack proper frames and need special configuration. - if (env.irb->fs().stublogue()) { - assertx(!isInlining(env)); - assertx(mode == EndCatchData::CatchMode::UnwindOnly); - auto const data = EndCatchData { - spOffBCFromIRSP(env), - EndCatchData::CatchMode::UnwindOnly, - EndCatchData::FrameMode::Stublogue, - EndCatchData::Teardown::NA, - std::nullopt - }; - gen(env, EndCatch, data, fp(env), sp(env)); - return catchBlock; - } + // VMSP is always synced at BeginCatch + auto const vmspOffset = spOffBCFromIRSP(env); - // Teardown::None can't be used without an empty stack. - assertx(IMPLIES(mode == EndCatchData::CatchMode::LocalsDecRefd, - spOffBCFromStackBase(env) == spOffEmpty(env))); - - // If we are unwinding from an inlined function, try a special logic that - // may eliminate the need to spill the current frame. - if (isInlining(env)) { - if (endCatchFromInlined(env, mode, exc)) return catchBlock; - } - - if (spillInlinedFrames(env)) { - gen(env, StVMFP, fp(env)); - gen(env, StVMPC, cns(env, uintptr_t(curSrcKey(env).pc()))); - gen(env, StVMReturnAddr, cns(env, 0)); - } + body(); - auto const teardown = mode == EndCatchData::CatchMode::LocalsDecRefd - ? EndCatchData::Teardown::None - : EndCatchData::Teardown::Full; - auto const offset = spOffBCFromIRSP(env); - auto const data = EndCatchData { - offset, - mode, - EndCatchData::FrameMode::Phplogue, - teardown, - offset - }; - gen(env, EndCatch, data, fp(env), sp(env)); + emitHandleException(env, mode, exc, vmspOffset); return catchBlock; }