Skip to content

Commit

Permalink
Deduplicate exception handling logic to emitHandleException()
Browse files Browse the repository at this point in the history
Summary:
Deduplicate the exception handling logic in makeCatchBlock() and
irgen-inlining's implEndCatchBlock() into emitHandleException().

Allows later diffs to:
- route Hack exceptions directly to Hack catch handlers
- implement emitThrow using emitHandleException()

Reviewed By: ricklavoie

Differential Revision: D51213504

fbshipit-source-id: f5cd04af238ec39755ca5363390fe0350af51fd9
  • Loading branch information
jano authored and facebook-github-bot committed Nov 10, 2023
1 parent 909cb5c commit fbf5ebc
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 66 deletions.
48 changes: 48 additions & 0 deletions hphp/runtime/vm/jit/irgen-control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,54 @@ void emitSelect(IRGS& env) {

//////////////////////////////////////////////////////////////////////

void emitHandleException(IRGS& env, EndCatchData::CatchMode mode, SSATmp* exc,
Optional<IRSPRelOffset> 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));
Expand Down
12 changes: 12 additions & 0 deletions hphp/runtime/vm/jit/irgen-control.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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<IRSPRelOffset> vmspOffset);

//////////////////////////////////////////////////////////////////////

}}
Expand Down
25 changes: 3 additions & 22 deletions hphp/runtime/vm/jit/irgen-inlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
49 changes: 5 additions & 44 deletions hphp/runtime/vm/jit/irgen-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit fbf5ebc

Please sign in to comment.