-
Notifications
You must be signed in to change notification settings - Fork 747
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
[EH] Add instructions for new proposal #6181
Changes from 4 commits
cdb8eb9
424c799
168b984
9026623
8bb08e5
54b4e1c
51e4efd
6eaa08c
b3888f8
19a3a12
5fe611d
a1568de
89a5e46
21407d7
5420500
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,13 @@ void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) { | |
func(name, sw->value ? sw->value->type : Type::none); | ||
} else if (auto* br = expr->dynCast<BrOn>()) { | ||
func(name, br->getSentType()); | ||
} else if (auto* tt = expr->dynCast<TryTable>()) { | ||
for (Index i = 0; i < tt->catchTags.size(); i++) { | ||
auto dest = tt->catchDests[i]; | ||
if (dest == name) { | ||
func(name, tt->sentTypes[i]); | ||
} | ||
} | ||
} else { | ||
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow | ||
} | ||
|
@@ -97,6 +104,10 @@ void operateOnScopeNameUsesAndSentValues(Expression* expr, T func) { | |
func(name, sw->value); | ||
} else if (auto* br = expr->dynCast<BrOn>()) { | ||
func(name, br->ref); | ||
} else if (auto* tt = expr->dynCast<TryTable>()) { | ||
// The values are supplied by throwing instructions, so we are unable to | ||
// know what they will be here. | ||
func(name, nullptr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} else { | ||
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -706,6 +706,11 @@ class EffectAnalyzer { | |
parent.delegateTargets.insert(curr->delegateTarget); | ||
} | ||
} | ||
void visitTryTable(TryTable* curr) { | ||
for (auto name : curr->catchDests) { | ||
parent.breakTargets.insert(name); | ||
} | ||
} | ||
void visitThrow(Throw* curr) { | ||
if (parent.tryDepth == 0) { | ||
parent.throws_ = true; | ||
|
@@ -715,6 +720,11 @@ class EffectAnalyzer { | |
if (parent.tryDepth == 0) { | ||
parent.throws_ = true; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to have truncated Rethrow's handling? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No that was intentional. So current There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, thanks! Makes sense. |
||
void visitThrowRef(ThrowRef* curr) { | ||
if (parent.tryDepth == 0) { | ||
parent.throws_ = true; | ||
} | ||
// traps when the arg is null | ||
parent.implicitTrap = true; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1152,6 +1152,10 @@ struct InfoCollector | |
#endif | ||
} | ||
} | ||
void visitTryTable(TryTable* curr) { | ||
// TODO: optimize when possible | ||
addRoot(curr); | ||
} | ||
void visitThrow(Throw* curr) { | ||
auto& operands = curr->operands; | ||
if (!isRelevant(operands)) { | ||
|
@@ -1165,6 +1169,10 @@ struct InfoCollector | |
} | ||
} | ||
void visitRethrow(Rethrow* curr) {} | ||
void visitThrowRef(ThrowRef* curr) { | ||
// TODO: optimize when possible | ||
addRoot(curr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is unreachable, like rethrow? So there is no value to add a root here for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed it, thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait, sorry, I had to refresh... |
||
} | ||
|
||
void visitTupleMake(TupleMake* curr) { | ||
if (isRelevant(curr->type)) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -846,6 +846,31 @@ class Builder { | |
Try* makeTry(Name name, Expression* body, Name delegateTarget, Type type) { | ||
return makeTry(name, body, {}, {}, delegateTarget, type, true); | ||
} | ||
TryTable* makeTryTable(Expression* body, | ||
const std::vector<Name>& catchTags, | ||
const std::vector<Name>& catchDests, | ||
const std::vector<bool>& catchRefs) { | ||
auto* ret = wasm.allocator.alloc<TryTable>(); | ||
ret->body = body; | ||
ret->catchTags.set(catchTags); | ||
ret->catchDests.set(catchDests); | ||
ret->catchRefs.set(catchRefs); | ||
ret->finalize(&wasm); | ||
return ret; | ||
} | ||
TryTable* makeTryTable(Expression* body, | ||
const std::vector<Name>& catchTags, | ||
const std::vector<Name>& catchDests, | ||
const std::vector<bool>& catchRefs, | ||
Type type) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we could unify pairs of functions like this using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will try that in a follow-up. |
||
auto* ret = wasm.allocator.alloc<TryTable>(); | ||
ret->body = body; | ||
ret->catchTags.set(catchTags); | ||
ret->catchDests.set(catchDests); | ||
ret->catchRefs.set(catchRefs); | ||
ret->finalize(type, &wasm); | ||
return ret; | ||
} | ||
Throw* makeThrow(Tag* tag, const std::vector<Expression*>& args) { | ||
return makeThrow(tag->name, args); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this comparing to
name
? The name should only be provided tofunc
(which can modify it) IIUC.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I think I was confused. Fixed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I think the original code was correct...
name
given here is a block label, and we should runfunc
only when thename
is the label we are targeting. For example:In this case, when analyzing
TryTable
, we shouldn't send bothi32
and(i32 exnref)
to a givenname
, which will mean the givenname
has two different types. We send the type only when the givenname
matches itssentType
's label.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks. So this is called multiple times for a single
TryTable
, once per name, and we need to handle the right name each time.Maybe worth handling
TryTable
outside of theoperateOnScopeNameUses
to avoid the potentially quadratic work? But if we think that will be incredibly rare maybe just a comment is enough.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though theoretically there can be any number of
catch
es, in practice there is no reason to use more than two (one for one ofcatch
/catch_ref
and the other for one ofcatch_all
/catch_all_ref
), unless you are trying to catch multiple language tags. And in LLVM we don't even generate twocatch
es: We only generate onecatch
orcatch_all
for a singletry
due to the structure of Windows EH IR, and I think this will be also the case for the new spec. Even though we assume a non-LLVM multi-language handling case I doubt this will go more than 3.