From 4a907b0a5ec1c25eef259ba54b387865edbe0451 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 18 Apr 2024 17:08:20 -0700 Subject: [Parser][NFC] Solve performance issue by adding maybeLabelidx (#6514) Creating an error in the parser is an extremely expensive operation for very large files because it has to traverse the input buffer and count newlines to compute the error message. Despite that, there are a few places were we create errors just to discard them and continue parsing. The most notable of these places was where we parsed the list of label index immediates for the br_table instruction. The parser determined the end of the list by intercepting the error produced when trying to parse one more label index. Fix this significant performance problem causing parsing to be quadratic by introducing and using `maybeLabelidx`, which tries to parse a label index but does not produce an error if it fails. --- src/parser/parsers.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'src/parser/parsers.h') diff --git a/src/parser/parsers.h b/src/parser/parsers.h index bcae62e14..bbb50b664 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -330,6 +330,9 @@ template Result elemidx(Ctx&); template Result dataidx(Ctx&); template Result localidx(Ctx&); template +MaybeResult maybeLabelidx(Ctx&, + bool inDelegate = false); +template Result labelidx(Ctx&, bool inDelegate = false); template Result tagidx(Ctx&); template Result typeuse(Ctx&); @@ -1969,16 +1972,18 @@ Result<> makeBreakTable(Ctx& ctx, Index pos, const std::vector& annotations) { std::vector labels; + // Parse at least one label; return an error only if we parse none. while (true) { - // Parse at least one label; return an error only if we parse none. - auto label = labelidx(ctx); - if (labels.empty()) { - CHECK_ERR(label); - } else if (label.getErr()) { + auto label = maybeLabelidx(ctx); + if (!label) { break; } + CHECK_ERR(label); labels.push_back(*label); } + if (labels.empty()) { + return ctx.in.err("expected label"); + } auto defaultLabel = labels.back(); labels.pop_back(); return ctx.makeSwitch(pos, annotations, labels, defaultLabel); @@ -2701,17 +2706,26 @@ template Result localidx(Ctx& ctx) { return ctx.in.err("expected local index or identifier"); } +template +Result labelidx(Ctx& ctx, bool inDelegate) { + if (auto idx = maybeLabelidx(ctx, inDelegate)) { + CHECK_ERR(idx); + return *idx; + } + return ctx.in.err("expected label index or identifier"); +} + // labelidx ::= x:u32 => x // | v:id => x (if labels[x] = v) template -Result labelidx(Ctx& ctx, bool inDelegate) { +MaybeResult maybeLabelidx(Ctx& ctx, bool inDelegate) { if (auto x = ctx.in.takeU32()) { return ctx.getLabelFromIdx(*x, inDelegate); } if (auto id = ctx.in.takeID()) { return ctx.getLabelFromName(*id, inDelegate); } - return ctx.in.err("expected label index or identifier"); + return {}; } // tagidx ::= x:u32 => x -- cgit v1.2.3