Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Parser] Support prologue and epilogue sourcemap annotations #6370

Merged
merged 2 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ full changeset diff at the end of each section.
Current Trunk
-------------

- (If new wat parser is enabled) Source map comments on `else` branches must
now be placed above the instruction inside the `else` branch rather than on
the `else` branch itself.

v117
----

Expand Down
22 changes: 15 additions & 7 deletions src/parser/context-decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ Result<> ParseDeclsCtx::addFunc(Name name,
ImportNames* import,
TypeUseT type,
std::optional<LocalsT>,
std::vector<Annotation>&& annotations,
Index pos) {
CHECK_ERR(checkImport(pos, import));
auto f = addFuncDecl(pos, name, import);
CHECK_ERR(f);
CHECK_ERR(addExports(in, wasm, *f, exports, ExternalKind::Function));
funcDefs.push_back({name, pos, Index(funcDefs.size())});
funcDefs.push_back(
{name, pos, Index(funcDefs.size()), std::move(annotations)});
return Ok{};
}

Expand Down Expand Up @@ -109,7 +111,8 @@ Result<> ParseDeclsCtx::addTable(Name name,
auto t = addTableDecl(pos, name, import, limits);
CHECK_ERR(t);
CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Table));
tableDefs.push_back({name, pos, Index(tableDefs.size())});
// TODO: table annotations
tableDefs.push_back({name, pos, Index(tableDefs.size()), {}});
return Ok{};
}

Expand Down Expand Up @@ -164,7 +167,8 @@ Result<> ParseDeclsCtx::addMemory(Name name,
auto m = addMemoryDecl(pos, name, import, type);
CHECK_ERR(m);
CHECK_ERR(addExports(in, wasm, *m, exports, ExternalKind::Memory));
memoryDefs.push_back({name, pos, Index(memoryDefs.size())});
// TODO: memory annotations
memoryDefs.push_back({name, pos, Index(memoryDefs.size()), {}});
return Ok{};
}

Expand Down Expand Up @@ -209,7 +213,8 @@ Result<> ParseDeclsCtx::addGlobal(Name name,
auto g = addGlobalDecl(pos, name, import);
CHECK_ERR(g);
CHECK_ERR(addExports(in, wasm, *g, exports, ExternalKind::Global));
globalDefs.push_back({name, pos, Index(globalDefs.size())});
// TODO: global annotations
globalDefs.push_back({name, pos, Index(globalDefs.size()), {}});
return Ok{};
}

Expand All @@ -228,7 +233,8 @@ Result<> ParseDeclsCtx::addElem(
name = Names::getValidElementSegmentName(wasm, name);
e->name = name;
}
elemDefs.push_back({name, pos, Index(wasm.elementSegments.size())});
// TODO: element segment annotations
elemDefs.push_back({name, pos, Index(wasm.elementSegments.size()), {}});
wasm.addElementSegment(std::move(e));
return Ok{};
}
Expand All @@ -252,7 +258,8 @@ Result<> ParseDeclsCtx::addData(Name name,
d->name = name;
}
d->data = std::move(data);
dataDefs.push_back({name, pos, Index(wasm.dataSegments.size())});
// TODO: data segment annotations
dataDefs.push_back({name, pos, Index(wasm.dataSegments.size()), {}});
wasm.addDataSegment(std::move(d));
return Ok{};
}
Expand Down Expand Up @@ -285,7 +292,8 @@ Result<> ParseDeclsCtx::addTag(Name name,
auto t = addTagDecl(pos, name, import);
CHECK_ERR(t);
CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Tag));
tagDefs.push_back({name, pos, Index(tagDefs.size())});
// TODO: tag annotations
tagDefs.push_back({name, pos, Index(tagDefs.size()), {}});
return Ok{};
}

Expand Down
29 changes: 22 additions & 7 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct DefPos {
Name name;
Index pos;
Index index;
std::vector<Annotation> annotations;
};

struct GlobalType {
Expand Down Expand Up @@ -406,7 +407,7 @@ struct NullInstrParserCtx {
TagLabelListT makeTagLabelList() { return Ok{}; }
void appendTagLabel(TagLabelListT&, TagIdxT, LabelIdxT) {}

void setSrcLoc(const Annotation&) {}
void setSrcLoc(const std::vector<Annotation>&) {}

Result<> makeUnreachable(Index, const std::vector<Annotation>&) {
return Ok{};
Expand Down Expand Up @@ -903,12 +904,14 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
void setOpen() {}
Result<> addSubtype(Index) { return Ok{}; }
void finishSubtype(Name name, Index pos) {
subtypeDefs.push_back({name, pos, Index(subtypeDefs.size())});
// TODO: type annotations
subtypeDefs.push_back({name, pos, Index(subtypeDefs.size()), {}});
}
size_t getRecGroupStartIndex() { return 0; }
void addRecGroup(Index, size_t) {}
void finishDeftype(Index pos) {
typeDefs.push_back({{}, pos, Index(typeDefs.size())});
// TODO: type annotations
typeDefs.push_back({{}, pos, Index(typeDefs.size()), {}});
}

Limits makeLimits(uint64_t n, std::optional<uint64_t> m) {
Expand Down Expand Up @@ -952,6 +955,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
ImportNames* import,
TypeUseT type,
std::optional<LocalsT>,
std::vector<Annotation>&&,
Index pos);

Result<Table*>
Expand Down Expand Up @@ -986,7 +990,8 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
if (!startDefs.empty()) {
return Err{"unexpected extra 'start' function"};
}
startDefs.push_back({{}, pos, 0});
// TODO: start function annotations.
startDefs.push_back({{}, pos, 0, {}});
return Ok{};
}

Expand Down Expand Up @@ -1240,6 +1245,7 @@ struct ParseModuleTypesCtx : TypeParserCtx<ParseModuleTypesCtx>,
ImportNames*,
TypeUse type,
std::optional<LocalsT> locals,
std::vector<Annotation>&&,
Index pos) {
auto& f = wasm.functions[index];
if (!type.type.isSignature()) {
Expand Down Expand Up @@ -1601,6 +1607,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
ImportNames*,
TypeUseT,
std::optional<LocalsT>,
std::vector<Annotation>&&,
Index) {
return Ok{};
}
Expand Down Expand Up @@ -1687,9 +1694,17 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return wasm.memories[0]->name;
}

void setSrcLoc(const Annotation& annotation) {
assert(annotation.kind == srcAnnotationKind);
Lexer lexer(annotation.contents);
void setSrcLoc(const std::vector<Annotation>& annotations) {
const Annotation* annotation = nullptr;
for (auto& a : annotations) {
if (a.kind == srcAnnotationKind) {
annotation = &a;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just moved code, but I a question: can there be more than one srcAnnotationKind? (seems like if so then the last wins?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and yes. Is there some other existing behavior I should try to match instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of one, so lgtm.

}
}
if (!annotation) {
return;
}
Lexer lexer(annotation->contents);
auto contents = lexer.takeKeyword();
if (!contents || !lexer.empty()) {
return;
Expand Down
36 changes: 19 additions & 17 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -842,20 +842,11 @@ template<typename Ctx> Result<uint32_t> tupleArity(Ctx& ctx) {
// Instructions
// ============

template<typename Ctx>
void setSrcLoc(Ctx& ctx, const std::vector<Annotation>& annotations) {
for (const auto& annotation : annotations) {
if (annotation.kind == srcAnnotationKind) {
ctx.setSrcLoc(annotation);
}
}
}

// blockinstr ::= block | loop | if-else | try-catch | try_table
template<typename Ctx>
MaybeResult<> foldedBlockinstr(Ctx& ctx,
const std::vector<Annotation>& annotations) {
setSrcLoc(ctx, annotations);
ctx.setSrcLoc(annotations);
if (auto i = block(ctx, annotations, true)) {
return i;
}
Expand All @@ -877,7 +868,7 @@ MaybeResult<> foldedBlockinstr(Ctx& ctx,
template<typename Ctx>
MaybeResult<> unfoldedBlockinstr(Ctx& ctx,
const std::vector<Annotation>& annotations) {
setSrcLoc(ctx, annotations);
ctx.setSrcLoc(annotations);
if (auto i = block(ctx, annotations, false)) {
return i;
}
Expand Down Expand Up @@ -910,7 +901,7 @@ MaybeResult<> blockinstr(Ctx& ctx, const std::vector<Annotation>& annotations) {
// plaininstr ::= ... all plain instructions ...
template<typename Ctx>
MaybeResult<> plaininstr(Ctx& ctx, const std::vector<Annotation>& annotations) {
setSrcLoc(ctx, annotations);
ctx.setSrcLoc(annotations);
auto pos = ctx.in.getPos();
auto keyword = ctx.in.takeKeyword();
if (!keyword) {
Expand Down Expand Up @@ -1059,6 +1050,7 @@ Result<typename Ctx::MemargT> memarg(Ctx& ctx, uint32_t n) {
// blocktype ::= (t:result)? => t? | x,I:typeuse => x if I = {}
template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx& ctx) {
auto pos = ctx.in.getPos();
auto initialLexer = ctx.in;

if (auto res = results(ctx)) {
CHECK_ERR(res);
Expand All @@ -1069,7 +1061,7 @@ template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx& ctx) {

// We either had no results or multiple results. Reset and parse again as a
// type use.
ctx.in.setIndex(pos);
ctx.in = initialLexer;
auto use = typeuse(ctx);
CHECK_ERR(use);

Expand Down Expand Up @@ -1136,6 +1128,7 @@ ifelse(Ctx& ctx, const std::vector<Annotation>& annotations, bool folded) {

if (folded) {
CHECK_ERR(foldedinstrs(ctx));
ctx.setSrcLoc(annotations);
}

ctx.makeIf(pos, annotations, label, *type);
Expand Down Expand Up @@ -2913,8 +2906,9 @@ template<typename Ctx> MaybeResult<> import_(Ctx& ctx) {
auto name = ctx.in.takeID();
auto type = typeuse(ctx);
CHECK_ERR(type);
CHECK_ERR(
ctx.addFunc(name ? *name : Name{}, {}, &names, *type, std::nullopt, pos));
// TODO: function import annotations
CHECK_ERR(ctx.addFunc(
name ? *name : Name{}, {}, &names, *type, std::nullopt, {}, pos));
} else if (ctx.in.takeSExprStart("table"sv)) {
auto name = ctx.in.takeID();
auto type = tabletype(ctx);
Expand Down Expand Up @@ -2956,6 +2950,8 @@ template<typename Ctx> MaybeResult<> import_(Ctx& ctx) {
// '(' 'import' mod:name nm:name ')' typeuse ')'
template<typename Ctx> MaybeResult<> func(Ctx& ctx) {
auto pos = ctx.in.getPos();
auto annotations = ctx.in.getAnnotations();

if (!ctx.in.takeSExprStart("func"sv)) {
return {};
}
Expand All @@ -2981,14 +2977,20 @@ template<typename Ctx> MaybeResult<> func(Ctx& ctx) {
localVars = *l;
}
CHECK_ERR(instrs(ctx));
ctx.setSrcLoc(ctx.in.takeAnnotations());
}

if (!ctx.in.takeRParen()) {
return ctx.in.err("expected end of function");
}

CHECK_ERR(
ctx.addFunc(name, *exports, import.getPtr(), *type, localVars, pos));
CHECK_ERR(ctx.addFunc(name,
*exports,
import.getPtr(),
*type,
localVars,
std::move(annotations),
pos));
return Ok{};
}

Expand Down
3 changes: 2 additions & 1 deletion src/parser/wat-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,11 @@ Result<> parseModule(Module& wasm, std::string_view input) {
for (Index i = 0; i < decls.funcDefs.size(); ++i) {
ctx.index = i;
auto* f = wasm.functions[i].get();
WithPosition with(ctx, decls.funcDefs[i].pos);
ctx.setSrcLoc(decls.funcDefs[i].annotations);
if (!f->imported()) {
CHECK_ERR(ctx.visitFunctionStart(f));
}
WithPosition with(ctx, decls.funcDefs[i].pos);
if (auto parsed = func(ctx)) {
CHECK_ERR(parsed);
} else {
Expand Down
18 changes: 18 additions & 0 deletions src/wasm/wasm-ir-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,17 @@ Result<Expression*> IRBuilder::build() {
}

void IRBuilder::setDebugLocation(const Function::DebugLocation& loc) {
DBG(std::cerr << "setting debugloc " << loc.fileIndex << ":" << loc.lineNumber
<< ":" << loc.columnNumber << "\n";);
debugLoc = loc;
}

void IRBuilder::applyDebugLoc(Expression* expr) {
if (debugLoc) {
if (func) {
DBG(std::cerr << "applying debugloc " << debugLoc->fileIndex << ":"
<< debugLoc->lineNumber << ":" << debugLoc->columnNumber
<< " to expression " << ShallowExpression{expr} << "\n");
func->debugLocations[expr] = *debugLoc;
}
debugLoc.reset();
Expand Down Expand Up @@ -672,6 +677,10 @@ Result<> IRBuilder::visitFunctionStart(Function* func) {
if (!scopeStack.empty()) {
return Err{"unexpected start of function"};
}
if (debugLoc) {
func->prologLocation.insert(*debugLoc);
debugLoc.reset();
}
scopeStack.push_back(ScopeCtx::makeFunc(func));
this->func = func;
return Ok{};
Expand Down Expand Up @@ -714,6 +723,11 @@ Result<> IRBuilder::visitTryTableStart(TryTable* trytable, Name label) {
}

Result<Expression*> IRBuilder::finishScope(Block* block) {
if (debugLoc) {
DBG(std::cerr << "discarding debugloc " << debugLoc->fileIndex << ":"
<< debugLoc->lineNumber << ":" << debugLoc->columnNumber
<< "\n");
}
debugLoc.reset();

if (scopeStack.empty() || scopeStack.back().isNone()) {
Expand Down Expand Up @@ -940,6 +954,10 @@ Result<> IRBuilder::visitEnd() {
if (scope.isNone()) {
return Err{"unexpected end"};
}
if (auto* func = scope.getFunction(); func && debugLoc) {
func->epilogLocation.insert(*debugLoc);
debugLoc.reset();
}
auto expr = finishScope(scope.getBlock());
CHECK_ERR(expr);

Expand Down
12 changes: 11 additions & 1 deletion test/lit/source-map.wast
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
;; RUN: wasm-opt %s -o %t.wasm -osm %t.map -g -q
;; RUN: wasm-opt %t.wasm -ism %t.map -q -o - -S | filecheck %s

;; RUN: wasm-opt %s --new-wat-parser -S -o - | filecheck %s

(module
;;@ src.cpp:0:1
(func $foo (param $x i32) (param $y i32)
;;@ src.cpp:10:1
(if
Expand All @@ -12,8 +15,11 @@
;;@ src.cpp:40:1
(local.get $y)
)
;; For the legacy parser
;;@ src.cpp:50:1
(then
;; For the new parser
;;@ src.cpp:50:1
(return)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the old parser doesn't roundtrip this properly and the new one does, is that correct? Perhaps add a comment to clarify that so it's obvious why we have these two 50:1 annotations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They can both round-trip properly, but the old one only if the annotation is on the then and the new one only if the annotation is on the return. Do you think this kind of breaking change is going to be an issue? We can make sure j2wasm is doing the right thing, but other users would be more difficult.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it hard to match the old behavior?

This doesn't seem like a dangerous breaking change to me, as our text format in general is not entirely standard nor stable, but we should document it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would be some very ad-hoc plumbing required to carry the annotation from the then to the first instruction inside the then, so I'd like to avoid it if it's not necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds ok to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a suggestion about where to document it? The changelog might make sense, but more so if we were actually enabling the new parser at the same time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the changelog. I agree it makes more sense when we enable the new parser. Maybe we can put a note in the changelog up above the current release notes, in preparation for enabling the new parser, to remind us, or something like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

)
)
Expand All @@ -24,10 +30,12 @@
;;@ src.cpp:80:1
(local.get $y)
)
;;@ src.cpp:90:1
)
)

;; CHECK: (func $foo (param $x i32) (param $y i32)
;; CHECK: ;;@ src.cpp:0:1
;; CHECK-NEXT: (func $foo (param $x i32) (param $y i32)
;; CHECK-NEXT: ;;@ src.cpp:10:1
;; CHECK-NEXT: (if
;; CHECK-NEXT: ;;@ src.cpp:20:1
Expand All @@ -49,3 +57,5 @@
;; CHECK-NEXT: ;;@ src.cpp:80:1
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: ;;@ src.cpp:90:1
;; CHECK-NEXT: )
Loading