Skip to content

Commit

Permalink
Apply patch. rdar://problem/97021541
Browse files Browse the repository at this point in the history
  • Loading branch information
rjepstein committed Aug 11, 2022
1 parent 08cc7f2 commit 78772ca
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 42 deletions.
14 changes: 14 additions & 0 deletions Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ void BytecodeDumper::dumpBlock(FunctionCodeBlockGenerator* block, const ModuleIn
}

dumper.dumpConstants();
dumper.dumpExceptionHandlers();

out.printf("\n");
}
Expand All @@ -383,6 +384,19 @@ void BytecodeDumper::dumpConstants()
}
}

void BytecodeDumper::dumpExceptionHandlers()
{
if (unsigned count = this->block()->numberOfExceptionHandlers()) {
this->m_out.printf("\nException Handlers:\n");
unsigned i = 0;
do {
const auto& handler = this->block()->exceptionHandler(i);
this->m_out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] tryDepth: [%4d] exceptionIndexOrDelegateTarget: [%4d] } %s\n", i + 1, handler.m_start, handler.m_end, handler.m_target, handler.m_tryDepth, handler.m_exceptionIndexOrDelegateTarget, handler.typeName().characters8());
++i;
} while (i < count);
}
}

CString BytecodeDumper::constantName(VirtualRegister index) const
{
FunctionCodeBlockGenerator* block = this->block();
Expand Down
1 change: 1 addition & 0 deletions Source/JavaScriptCore/bytecode/BytecodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class BytecodeDumper final : public JSC::BytecodeDumper<FunctionCodeBlockGenerat
using JSC::BytecodeDumper<FunctionCodeBlockGenerator>::BytecodeDumper;

void dumpConstants();
void dumpExceptionHandlers();
CString constantName(VirtualRegister index) const final;
CString formatConstant(Type, uint64_t) const;
};
Expand Down
22 changes: 14 additions & 8 deletions Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ class AirIRGenerator {
return fail(__VA_ARGS__); \
} while (0)

AirIRGenerator(const ModuleInformation&, B3::Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, unsigned functionIndex, TierUpCount*, const Signature&);
AirIRGenerator(const ModuleInformation&, B3::Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, unsigned functionIndex, std::optional<bool> hasExceptionHandlers, TierUpCount*, const Signature&);

void finalizeEntrypoints();

Expand Down Expand Up @@ -858,6 +858,7 @@ class AirIRGenerator {
GPRReg m_wasmContextInstanceGPR { InvalidGPRReg };
GPRReg m_prologueWasmContextGPR { InvalidGPRReg };
bool m_makesCalls { false };
std::optional<bool> m_hasExceptionHandlers;

HashMap<BlockSignature, B3::Type> m_tupleMap;
// This is only filled if we are dumping IR.
Expand Down Expand Up @@ -929,14 +930,15 @@ void AirIRGenerator::restoreWasmContextInstance(BasicBlock* block, TypedTmp inst
emitPatchpoint(block, patchpoint, Tmp(), instance);
}

AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, unsigned functionIndex, TierUpCount* tierUp, const Signature& signature)
AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, unsigned functionIndex, std::optional<bool> hasExceptionHandlers, TierUpCount* tierUp, const Signature& signature)
: m_info(info)
, m_mode(mode)
, m_functionIndex(functionIndex)
, m_tierUp(tierUp)
, m_proc(procedure)
, m_code(m_proc.code())
, m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
, m_hasExceptionHandlers(hasExceptionHandlers)
, m_numImportFunctions(info.importFunctionCount())
{
m_currentBlock = m_code.addBlock();
Expand Down Expand Up @@ -992,12 +994,13 @@ AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& pro
const int32_t checkSize = m_makesCalls ? (wasmFrameSize + extraFrameSize).value() : wasmFrameSize.value();
bool needUnderflowCheck = static_cast<unsigned>(checkSize) > Options::reservedZoneSize();
bool needsOverflowCheck = m_makesCalls || wasmFrameSize >= static_cast<int32_t>(minimumParentCheckSize) || needUnderflowCheck;
bool mayHaveExceptionHandlers = !m_hasExceptionHandlers || m_hasExceptionHandlers.value();

if ((needsOverflowCheck || m_usesInstanceValue) && Context::useFastTLS())
if ((needsOverflowCheck || m_usesInstanceValue || mayHaveExceptionHandlers) && Context::useFastTLS())
jit.loadWasmContextInstance(m_prologueWasmContextGPR);

// We need to setup JSWebAssemblyInstance in |this| slot first.
if (m_catchEntrypoints.size()) {
if (mayHaveExceptionHandlers) {
GPRReg scratch = wasmCallingConvention().prologueScratchGPRs[0];
jit.loadPtr(CCallHelpers::Address(m_prologueWasmContextGPR, Instance::offsetOfOwner()), scratch);
jit.store64(scratch, CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::thisArgument * sizeof(Register)));
Expand All @@ -1006,6 +1009,9 @@ AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& pro
// This allows leaf functions to not do stack checks if their frame size is within
// certain limits since their caller would have already done the check.
if (needsOverflowCheck) {
if (mayHaveExceptionHandlers)
jit.store32(CCallHelpers::TrustedImm32(PatchpointExceptionHandle::s_invalidCallSiteIndex), CCallHelpers::tagFor(CallFrameSlot::argumentCountIncludingThis));

GPRReg scratch = wasmCallingConvention().prologueScratchGPRs[0];
jit.addPtr(CCallHelpers::TrustedImm32(-checkSize), GPRInfo::callFrameRegister, scratch);
MacroAssembler::JumpList overflow;
Expand Down Expand Up @@ -3873,7 +3879,7 @@ auto AirIRGenerator::origin() -> B3::Origin
return B3::Origin();
}

Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, uint32_t functionIndex, TierUpCount* tierUp)
Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, TierUpCount* tierUp)
{
auto result = makeUnique<InternalFunction>();

Expand All @@ -3896,7 +3902,7 @@ Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(Compilati

procedure.setOptLevel(Options::webAssemblyBBQAirOptimizationLevel());

AirIRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, functionIndex, tierUp, signature);
AirIRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, functionIndex, hasExceptionHandlers, tierUp, signature);
FunctionParser<AirIRGenerator> parser(irGenerator, function.data.data(), function.data.size(), signature, info);
WASM_FAIL_IF_HELPER_FAILS(parser.parse());

Expand Down Expand Up @@ -5470,7 +5476,7 @@ PatchpointExceptionHandle AirIRGenerator::preparePatchpointForExceptions(B3::Pat
{
++m_callSiteIndex;
if (!m_tryCatchDepth)
return { };
return { m_hasExceptionHandlers };

unsigned numLiveValues = 0;
forEachLiveValue([&] (Tmp tmp) {
Expand All @@ -5480,7 +5486,7 @@ PatchpointExceptionHandle AirIRGenerator::preparePatchpointForExceptions(B3::Pat

patch->effects.exitsSideways = true;

return PatchpointExceptionHandle { m_callSiteIndex, numLiveValues };
return { m_hasExceptionHandlers, m_callSiteIndex, numLiveValues };
}

} } // namespace JSC::Wasm
Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/wasm/WasmAirIRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

namespace JSC { namespace Wasm {

Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, uint32_t functionIndex, TierUpCount* = nullptr);
Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, TierUpCount* = nullptr);

} } // namespace JSC::Wasm

Expand Down
31 changes: 19 additions & 12 deletions Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class B3IRGenerator {
return fail(__VA_ARGS__); \
} while (0)

B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, MemoryMode, CompilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount*);
B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, MemoryMode, CompilationMode, unsigned functionIndex, std::optional<bool> hasExceptionHandlers, unsigned loopIndexForOSREntry, TierUpCount*);

PartialResult WARN_UNUSED_RETURN addArguments(const Signature&);
PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
Expand Down Expand Up @@ -548,10 +548,10 @@ class B3IRGenerator {
GPRReg m_boundsCheckingSizeGPR { InvalidGPRReg };
GPRReg m_wasmContextInstanceGPR { InvalidGPRReg };
bool m_makesCalls { false };
std::optional<bool> m_hasExceptionHandlers;

Value* m_instanceValue { nullptr }; // Always use the accessor below to ensure the instance value is materialized when used.
bool m_usesInstanceValue { false };
bool m_hasCatch { false };
Value* instanceValue()
{
m_usesInstanceValue = true;
Expand Down Expand Up @@ -609,7 +609,7 @@ void B3IRGenerator::restoreWasmContextInstance(Procedure& proc, BasicBlock* bloc
});
}

B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount* tierUp)
B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, std::optional<bool> hasExceptionHandlers, unsigned loopIndexForOSREntry, TierUpCount* tierUp)
: m_info(info)
, m_mode(mode)
, m_compilationMode(compilationMode)
Expand All @@ -620,6 +620,7 @@ B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure
, m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
, m_osrEntryScratchBufferSize(osrEntryScratchBufferSize)
, m_constantInsertionValues(m_proc)
, m_hasExceptionHandlers(hasExceptionHandlers)
, m_numImportFunctions(info.importFunctionCount())
{
m_topLevelBlock = m_proc.addBlock();
Expand Down Expand Up @@ -853,17 +854,24 @@ void B3IRGenerator::insertEntrySwitch()

void B3IRGenerator::insertConstants()
{
bool mayHaveExceptionHandlers = !m_hasExceptionHandlers || m_hasExceptionHandlers.value();

Value* invalidCallSiteIndex = nullptr;
if (mayHaveExceptionHandlers)
invalidCallSiteIndex = constant(B3::Int32, PatchpointExceptionHandle::s_invalidCallSiteIndex, Origin());
m_constantInsertionValues.execute(m_proc.at(0));

if (!m_hasCatch)
if (!mayHaveExceptionHandlers)
return;

Value* jsInstance = m_proc.add<MemoryValue>(Load, pointerType(), Origin(), instanceValue(), safeCast<int32_t>(Instance::offsetOfOwner()));
Value* store = m_proc.add<B3::MemoryValue>(B3::Store, Origin(), jsInstance, framePointer(), safeCast<int32_t>(CallFrameSlot::thisArgument * sizeof(Register)));
Value* storeThis = m_proc.add<B3::MemoryValue>(B3::Store, Origin(), jsInstance, framePointer(), safeCast<int32_t>(CallFrameSlot::thisArgument * sizeof(Register)));
Value* storeCallSiteIndex = m_proc.add<B3::MemoryValue>(B3::Store, Origin(), invalidCallSiteIndex, framePointer(), safeCast<int32_t>(CallFrameSlot::argumentCountIncludingThis * sizeof(Register) + TagOffset));

BasicBlock* block = m_rootBlocks[0];
m_constantInsertionValues.insertValue(0, jsInstance);
m_constantInsertionValues.insertValue(0, store);
m_constantInsertionValues.insertValue(0, storeThis);
m_constantInsertionValues.insertValue(0, storeCallSiteIndex);
m_constantInsertionValues.execute(block);
}

Expand Down Expand Up @@ -2524,7 +2532,7 @@ PatchpointExceptionHandle B3IRGenerator::preparePatchpointForExceptions(BasicBlo
{
++m_callSiteIndex;
if (!m_tryCatchDepth)
return { };
return { m_hasExceptionHandlers };

Vector<Value*> liveValues;
Origin origin = this->origin();
Expand All @@ -2544,7 +2552,7 @@ PatchpointExceptionHandle B3IRGenerator::preparePatchpointForExceptions(BasicBlo
patch->effects.exitsSideways = true;
patch->appendVectorWithRep(liveValues, ValueRep::LateColdAny);

return PatchpointExceptionHandle { m_callSiteIndex, static_cast<unsigned>(liveValues.size()) };
return { m_hasExceptionHandlers, m_callSiteIndex, static_cast<unsigned>(liveValues.size()) };
}

auto B3IRGenerator::addCatchToUnreachable(unsigned exceptionIndex, const Signature& signature, ControlType& data, ResultList& results) -> PartialResult
Expand Down Expand Up @@ -2574,7 +2582,6 @@ auto B3IRGenerator::addCatchAllToUnreachable(ControlType& data) -> PartialResult

Value* B3IRGenerator::emitCatchImpl(CatchKind kind, ControlType& data, unsigned exceptionIndex)
{
m_hasCatch = true;
m_currentBlock = m_proc.addBlock();
m_rootBlocks.append(m_currentBlock);
m_stackSize = data.stackSize();
Expand Down Expand Up @@ -2814,7 +2821,7 @@ B3::Value* B3IRGenerator::createCallPatchpoint(BasicBlock* block, Origin origin,

m_proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), wasmCallInfo.headerAndArgumentStackSizeInBytes));

Box<PatchpointExceptionHandle> exceptionHandle = Box<PatchpointExceptionHandle>::create();
Box<PatchpointExceptionHandle> exceptionHandle = Box<PatchpointExceptionHandle>::create(m_hasExceptionHandlers);

B3::Type returnType = toB3ResultType(&signature);
PatchpointValue* patchpoint = m_proc.add<PatchpointValue>(returnType, origin);
Expand Down Expand Up @@ -3138,7 +3145,7 @@ static bool shouldDumpIRFor(uint32_t functionIndex)
return dumpAllowlist->shouldDumpWasmFunction(functionIndex);
}

Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* tierUp)
Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, uint32_t loopIndexForOSREntry, TierUpCount* tierUp)
{
auto result = makeUnique<InternalFunction>();

Expand Down Expand Up @@ -3173,7 +3180,7 @@ Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationC
? Options::webAssemblyBBQB3OptimizationLevel()
: Options::webAssemblyOMGOptimizationLevel());

B3IRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, mode, compilationMode, functionIndex, loopIndexForOSREntry, tierUp);
B3IRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, mode, compilationMode, functionIndex, hasExceptionHandlers, loopIndexForOSREntry, tierUp);
FunctionParser<B3IRGenerator> parser(irGenerator, function.data.data(), function.data.size(), signature, info);
WASM_FAIL_IF_HELPER_FAILS(parser.parse());

Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct CompilationContext {
Box<PCToCodeOriginMap> pcToCodeOriginMap;
};

Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* = nullptr);
Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, uint32_t loopIndexForOSREntry, TierUpCount* = nullptr);

void computePCToCodeOriginMap(CompilationContext&, LinkBuffer&);

Expand Down
7 changes: 4 additions & 3 deletions Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ namespace WasmBBQPlanInternal {
static constexpr bool verbose = false;
}

BBQPlan::BBQPlan(Context* context, Ref<ModuleInformation> moduleInformation, uint32_t functionIndex, CalleeGroup* calleeGroup, CompletionTask&& completionTask)
BBQPlan::BBQPlan(Context* context, Ref<ModuleInformation> moduleInformation, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, CalleeGroup* calleeGroup, CompletionTask&& completionTask)
: EntryPlan(context, WTFMove(moduleInformation), CompilerMode::FullCompile, WTFMove(completionTask))
, m_calleeGroup(calleeGroup)
, m_functionIndex(functionIndex)
, m_hasExceptionHandlers(hasExceptionHandlers)
{
ASSERT(Options::useBBQJIT());
setMode(m_calleeGroup->mode());
Expand Down Expand Up @@ -220,9 +221,9 @@ std::unique_ptr<InternalFunction> BBQPlan::compileFunction(uint32_t functionInde
forceUsingB3 = true;

if (forceUsingB3)
parseAndCompileResult = parseAndCompile(context, function, signature, unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, UINT32_MAX, tierUp);
parseAndCompileResult = parseAndCompile(context, function, signature, unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, m_hasExceptionHandlers, UINT32_MAX, tierUp);
else
parseAndCompileResult = parseAndCompileAir(context, function, signature, unlinkedWasmToWasmCalls, m_moduleInformation.get(), m_mode, functionIndex, tierUp);
parseAndCompileResult = parseAndCompileAir(context, function, signature, unlinkedWasmToWasmCalls, m_moduleInformation.get(), m_mode, functionIndex, m_hasExceptionHandlers, tierUp);

if (UNLIKELY(!parseAndCompileResult)) {
Locker locker { m_lock };
Expand Down
3 changes: 2 additions & 1 deletion Source/JavaScriptCore/wasm/WasmBBQPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class BBQPlan final : public EntryPlan {

using Base::Base;

BBQPlan(Context*, Ref<ModuleInformation>, uint32_t functionIndex, CalleeGroup*, CompletionTask&&);
BBQPlan(Context*, Ref<ModuleInformation>, uint32_t functionIndex, std::optional<bool> hasExceptionHandlers, CalleeGroup*, CompletionTask&&);

bool hasWork() const final
{
Expand Down Expand Up @@ -91,6 +91,7 @@ class BBQPlan final : public EntryPlan {

RefPtr<CalleeGroup> m_calleeGroup { nullptr };
uint32_t m_functionIndex;
std::optional<bool> m_hasExceptionHandlers;
};


Expand Down
17 changes: 17 additions & 0 deletions Source/JavaScriptCore/wasm/WasmHandlerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "CodeLocation.h"
#include <wtf/Forward.h>
#include <wtf/text/ASCIILiteral.h>

namespace JSC {
namespace Wasm {
Expand Down Expand Up @@ -65,6 +66,22 @@ struct UnlinkedHandlerInfo : public HandlerInfoBase {
m_tryDepth = tryDepth;
m_exceptionIndexOrDelegateTarget = exceptionIndexOrDelegateTarget;
}

ASCIILiteral typeName() const
{
switch (m_type) {
case HandlerType::Catch:
return "catch"_s;
case HandlerType::CatchAll:
return "catchall"_s;
case HandlerType::Delegate:
return "delegate"_s;
default:
ASSERT_NOT_REACHED();
break;
}
return ASCIILiteral::null();
}
};

struct HandlerInfo : public HandlerInfoBase {
Expand Down
Loading

0 comments on commit 78772ca

Please sign in to comment.