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

Stack switching proposal support #7041

Merged
merged 31 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
14af574
Stack switching proposal support
dhil Nov 4, 2024
edbc438
Address the 'easy' bits of Thomas' feedback
dhil Nov 5, 2024
c0d8648
Deduplicate the parsing logic for resume tables
dhil Nov 5, 2024
98f6314
Use inherited the 'type' member to track the continuation type in
dhil Nov 5, 2024
c407262
Format
dhil Nov 5, 2024
15fcbc6
Remove PrintSExpression::visit{Resume,ResumeThrow,StackSwitch}
dhil Nov 6, 2024
d1866bc
Don't (re)compute sentTypes for resume and resume_throw.
dhil Nov 6, 2024
2b06c76
[fuzz] Skip stack switching tests.
dhil Nov 6, 2024
3b339f9
Abstract shared logic for reading resume tables.
dhil Nov 6, 2024
0886451
Encode on-clauses using only two parallel vectors.
dhil Nov 6, 2024
d76f260
Return resumetable rather than taking it as a reference.
dhil Nov 7, 2024
1c2ed8a
Revert "Don't (re)compute sentTypes for resume and resume_throw."
dhil Nov 7, 2024
c8bf255
Propagate Type::unreachable in switch.
dhil Nov 7, 2024
9e16e47
Compute sentTypes for resumetables upon construction.
dhil Nov 8, 2024
157552a
WIP
dhil Nov 11, 2024
480843d
Check for unreachable continuation types.
dhil Nov 12, 2024
c8d345a
Compute resume table sent types during expression construction.
dhil Nov 13, 2024
0110dd5
Add switch lit test
dhil Nov 13, 2024
f418774
Fix unreachable type printing
dhil Nov 18, 2024
3bedcb5
Merge
dhil Nov 20, 2024
b1d65ce
Read sentTypes off label types.
dhil Nov 21, 2024
c549cd7
[WIP] Eliminate type immediate members.
dhil Nov 28, 2024
6a20680
Merge with upstream
dhil Nov 28, 2024
2a3fabe
Fix lint
dhil Dec 2, 2024
d19763c
Eliminate type immediates from stack switching instructions
dhil Dec 3, 2024
0e5caf2
Merge with upstream
dhil Jan 28, 2025
640aa92
Merge branch 'main' of github.com:WebAssembly/binaryen into stack-swi…
dhil Jan 28, 2025
4b6b93a
Run update_lit_tests
dhil Jan 28, 2025
9a8bb46
Rebuild and run update_lit_tests
dhil Jan 28, 2025
1d82c8b
Format
dhil Jan 28, 2025
60aed28
Update stack switching lit tests
dhil Jan 28, 2025
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
51 changes: 4 additions & 47 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1194,61 +1194,17 @@ class Builder {
ret->finalize(&wasm);
return ret;
}
template<typename ResumeOrResumeThrow>
std::vector<Type> computeResumeTableSentTypes(ResumeOrResumeThrow* curr) {
static_assert(std::is_base_of<Resume, ResumeOrResumeThrow>::value ||
std::is_base_of<ResumeThrow, ResumeOrResumeThrow>::value);
assert(curr->handlerBlocks.size() == curr->handlerTags.size());

// Let $tag be a tag with type [tgp*] -> [tgr*]. Let $ct be a continuation
// type (cont $ft), where $ft is [ctp*] -> [ctr*]. Then an instruction
// (resume $ct ... (tag $tag $block) ... ) causes $block to receive values
// of the following types when suspending to $tag: tgp* (ref $ct') where ct'
// = (cont $ft') and ft' = [tgr*] -> [ctr*].
//
std::vector<Type> sentTypes;
sentTypes.reserve(curr->handlerTags.size());
auto contSig = curr->contType.getContinuation().type.getSignature();
auto& ctrs = contSig.params;
for (Index i = 0; i < curr->handlerTags.size(); i++) {
if (curr->handlerBlocks[i].isNull()) {
sentTypes[i] = Type::none;
continue;
}

auto& tag = curr->handlerTags[i];
auto& tagSig = wasm.getTag(tag)->sig;

auto& tgps = tagSig.params;
auto& tgrs = tagSig.results;

HeapType ftPrime{Signature(tgrs, ctrs)};
HeapType ctPrime{Continuation(ftPrime)};
Type ctPrimeRef(ctPrime, Nullability::NonNullable);

if (tgps.size() > 0) {
TypeList sentValueTypes;
sentValueTypes.reserve(tgps.size() + 1);

sentValueTypes.insert(sentValueTypes.begin(), tgps.begin(), tgps.end());
sentValueTypes.push_back(ctPrimeRef);
sentTypes[i] = Type(sentValueTypes);
} else {
sentTypes[i] = ctPrimeRef;
}
}
return sentTypes;
}
Resume* makeResume(HeapType contType,
const std::vector<Name>& handlerTags,
const std::vector<Name>& handlerBlocks,
const std::vector<Type>& sentTypes,
const std::vector<Expression*>& operands,
Expression* cont) {
auto* ret = wasm.allocator.alloc<Resume>();
ret->contType = contType;
ret->handlerTags.set(handlerTags);
ret->handlerBlocks.set(handlerBlocks);
ret->sentTypes.set(computeResumeTableSentTypes<Resume>(ret));
ret->sentTypes.set(sentTypes);
ret->operands.set(operands);
ret->cont = cont;
ret->finalize(&wasm);
Expand All @@ -1258,14 +1214,15 @@ class Builder {
Name tag,
const std::vector<Name>& handlerTags,
const std::vector<Name>& handlerBlocks,
const std::vector<Type>& sentTypes,
const std::vector<Expression*>& operands,
Expression* cont) {
auto* ret = wasm.allocator.alloc<ResumeThrow>();
ret->contType = contType;
ret->tag = tag;
ret->handlerTags.set(handlerTags);
ret->handlerBlocks.set(handlerBlocks);
ret->sentTypes.set(computeResumeTableSentTypes<ResumeThrow>(ret));
ret->sentTypes.set(sentTypes);
ret->operands.set(operands);
ret->cont = cont;
ret->finalize(&wasm);
Expand Down
48 changes: 48 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7981,6 +7981,52 @@ static void readResumeTable(WasmBinaryReader* reader, ResumeType* curr) {
}
}

template<typename ResumeOrResumeThrow>
static void computeResumeTableSentTypes(Module& wasm,
ResumeOrResumeThrow* curr) {
static_assert(std::is_base_of<Resume, ResumeOrResumeThrow>::value ||
std::is_base_of<ResumeThrow, ResumeOrResumeThrow>::value);
assert(curr->handlerBlocks.size() == curr->handlerTags.size());

// Let $tag be a tag with type [tgp*] -> [tgr*]. Let $ct be a continuation
// type (cont $ft), where $ft is [ctp*] -> [ctr*]. Then an instruction
// (resume $ct ... (tag $tag $block) ... ) causes $block to receive values
// of the following types when suspending to $tag: tgp* (ref $ct') where ct'
// = (cont $ft') and ft' = [tgr*] -> [ctr*].
//
curr->sentTypes.reserve(curr->handlerTags.size());
auto contSig = curr->contType.getContinuation().type.getSignature();
auto& ctrs = contSig.params;
for (Index i = 0; i < curr->handlerTags.size(); i++) {
Type sentType;
if (curr->handlerBlocks[i].isNull()) {
sentType = Type::none;
} else {
auto& tag = curr->handlerTags[i];
auto& tagSig = wasm.getTag(tag)->sig;

auto& tgps = tagSig.params;
auto& tgrs = tagSig.results;

HeapType ftPrime{Signature(tgrs, ctrs)};
HeapType ctPrime{Continuation(ftPrime)};
Type ctPrimeRef(ctPrime, Nullability::NonNullable);
dhil marked this conversation as resolved.
Show resolved Hide resolved

if (tgps.size() > 0) {
TypeList sentValueTypes;
sentValueTypes.reserve(tgps.size() + 1);

sentValueTypes.insert(sentValueTypes.begin(), tgps.begin(), tgps.end());
sentValueTypes.push_back(ctPrimeRef);
sentType = Type(sentValueTypes);
} else {
sentType = ctPrimeRef;
}
}
curr->sentTypes.push_back(sentType);
}
}

void WasmBinaryReader::visitResume(Resume* curr) {

curr->contType = getIndexedHeapType();
Expand All @@ -7990,6 +8036,7 @@ void WasmBinaryReader::visitResume(Resume* curr) {
}

readResumeTable<Resume>(this, curr);
computeResumeTableSentTypes<Resume>(wasm, curr);

curr->cont = popNonVoidExpression();

Expand All @@ -8014,6 +8061,7 @@ void WasmBinaryReader::visitResumeThrow(ResumeThrow* curr) {
tagRefs[exnTagIndex].push_back(&curr->tag);

readResumeTable<ResumeThrow>(this, curr);
computeResumeTableSentTypes<ResumeThrow>(wasm, curr);

curr->cont = popNonVoidExpression();

Expand Down
63 changes: 60 additions & 3 deletions src/wasm/wasm-ir-builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,55 @@ Result<> IRBuilder::makeSuspend(Name tag) {
return Ok{};
}

static std::vector<Type>
computeResumeTableSentTypes(Module& wasm,
const Signature& contSig,
const std::vector<Name>& handlerTags,
const std::vector<Name> handlerBlocks) {
assert(handlerBlocks.size() == handlerTags.size());

// Let $tag be a tag with type [tgp*] -> [tgr*]. Let $ct be a continuation
// type (cont $ft), where $ft is [ctp*] -> [ctr*]. Then an instruction
// (resume $ct ... (tag $tag $block) ... ) causes $block to receive values
// of the following types when suspending to $tag: tgp* (ref $ct') where ct'
// = (cont $ft') and ft' = [tgr*] -> [ctr*].
//
std::vector<Type> sentTypes;
sentTypes.reserve(handlerTags.size());
auto& ctrs = contSig.params;
for (Index i = 0; i < handlerTags.size(); i++) {
Type sentType;
if (handlerBlocks[i].isNull()) {
sentType = Type::none;
} else {
auto& tag = handlerTags[i];
auto& tagSig = wasm.getTag(tag)->sig;

auto& tgps = tagSig.params;
auto& tgrs = tagSig.results;

HeapType ftPrime{Signature(tgrs, ctrs)};
HeapType ctPrime{Continuation(ftPrime)};
Type ctPrimeRef(ctPrime, Nullability::NonNullable);
dhil marked this conversation as resolved.
Show resolved Hide resolved

if (tgps.size() > 0) {
TypeList sentValueTypes;
sentValueTypes.reserve(tgps.size() + 1);

sentValueTypes.insert(sentValueTypes.begin(), tgps.begin(), tgps.end());
sentValueTypes.push_back(ctPrimeRef);
sentType = Type(sentValueTypes);
} else {
sentType = ctPrimeRef;
}
}
sentTypes.push_back(sentType);
}
assert(sentTypes.size() == handlerTags.size() &&
sentTypes.size() == handlerBlocks.size());
return sentTypes;
}

Result<>
IRBuilder::makeResume(HeapType ct,
const std::vector<Name>& tags,
Expand All @@ -1969,9 +2018,13 @@ IRBuilder::makeResume(HeapType ct,
labelNames.push_back(Name());
}
}

std::vector<Type> sentTypes =
computeResumeTableSentTypes(wasm, contSig, tags, labelNames);
curr.sentTypes.resize(sentTypes.size());
assert(sentTypes.size() == labelNames.size());
std::vector<Expression*> operands(curr.operands.begin(), curr.operands.end());
push(builder.makeResume(ct, tags, labelNames, operands, curr.cont));
push(
builder.makeResume(ct, tags, labelNames, sentTypes, operands, curr.cont));
return Ok{};
}

Expand All @@ -1987,6 +2040,7 @@ IRBuilder::makeResumeThrow(HeapType ct,
return Err{"expected continuation type"};
}
ResumeThrow curr(wasm.allocator);
auto contSig = ct.getContinuation().type.getSignature();
curr.contType = ct;
curr.tag = tag;
curr.operands.resize(wasm.getTag(tag)->sig.params.size());
Expand All @@ -2003,9 +2057,12 @@ IRBuilder::makeResumeThrow(HeapType ct,
labelNames.push_back(Name());
}
}
std::vector<Type> sentTypes =
computeResumeTableSentTypes(wasm, contSig, tags, labelNames);

std::vector<Expression*> operands(curr.operands.begin(), curr.operands.end());
push(builder.makeResumeThrow(ct, tag, tags, labelNames, operands, curr.cont));
push(builder.makeResumeThrow(
ct, tag, tags, labelNames, sentTypes, operands, curr.cont));
return Ok{};
}

Expand Down
86 changes: 0 additions & 86 deletions src/wasm/wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,47 +1387,6 @@ void Suspend::finalize(Module* wasm) {
}
}

static void populateResumeSentTypes(Resume* curr, Module* wasm) {
if (!wasm) {
return;
}

const Signature& contSig =
curr->contType.getContinuation().type.getSignature();

// Let $tag be a tag with type [tgp*] -> [tgr*]. Let $ct be a continuation
// type (cont $ft), where $ft is [ctp*] -> [ctr*]. Then an instruction (resume
// $ct ... (tag $tag $block) ... ) causes $block to receive values of the
// following types when suspending to $tag: tgp* (ref $ct') where ct' = (cont
// $ft') and ft' = [tgr*] -> [ctr*].
//
auto& ctrs = contSig.results;
curr->sentTypes.clear();
curr->sentTypes.resize(curr->handlerTags.size());
for (Index i = 0; i < curr->handlerTags.size(); i++) {
auto& tag = curr->handlerTags[i];
auto& tagSig = wasm->getTag(tag)->sig;

auto& tgps = tagSig.params;
auto& tgrs = tagSig.results;

HeapType ftPrime{Signature(tgrs, ctrs)};
HeapType ctPrime{Continuation(ftPrime)};
Type ctPrimeRef(ctPrime, Nullability::NonNullable);

if (tgps.size() > 0) {
TypeList sentValueTypes;
sentValueTypes.reserve(tgps.size() + 1);

sentValueTypes.insert(sentValueTypes.begin(), tgps.begin(), tgps.end());
sentValueTypes.push_back(ctPrimeRef);
curr->sentTypes[i] = Type(sentValueTypes);
} else {
curr->sentTypes[i] = ctPrimeRef;
}
}
}

void Resume::finalize(Module* wasm) {
if (cont->type == Type::unreachable) {
type = Type::unreachable;
Expand All @@ -1436,49 +1395,6 @@ void Resume::finalize(Module* wasm) {
this->contType.getContinuation().type.getSignature();
type = contSig.results;
}

populateResumeSentTypes(this, wasm);
}

static void populateResumeThrowSentTypes(ResumeThrow* curr, Module* wasm) {
if (!wasm) {
return;
}

const Signature& contSig =
curr->contType.getContinuation().type.getSignature();

// Let $tag be a tag with type [tgp*] -> [tgr*]. Let $ct be a continuation
// type (cont $ft), where $ft is [ctp*] -> [ctr*]. Then an instruction (resume
// $ct ... (tag $tag $block) ... ) causes $block to receive values of the
// following types when suspending to $tag: tgp* (ref $ct') where ct' = (cont
// $ft') and ft' = [tgr*] -> [ctr*].
//
auto& ctrs = contSig.results;
curr->sentTypes.clear();
curr->sentTypes.resize(curr->handlerTags.size());
for (Index i = 0; i < curr->handlerTags.size(); i++) {
auto& tag = curr->handlerTags[i];
auto& tagSig = wasm->getTag(tag)->sig;

auto& tgps = tagSig.params;
auto& tgrs = tagSig.results;

HeapType ftPrime{Signature(tgrs, ctrs)};
HeapType ctPrime{Continuation(ftPrime)};
Type ctPrimeRef(ctPrime, Nullability::NonNullable);

if (tgps.size() > 0) {
TypeList sentValueTypes;
sentValueTypes.reserve(tgps.size() + 1);

sentValueTypes.insert(sentValueTypes.begin(), tgps.begin(), tgps.end());
sentValueTypes.push_back(ctPrimeRef);
curr->sentTypes[i] = Type(sentValueTypes);
} else {
curr->sentTypes[i] = ctPrimeRef;
}
}
}

void ResumeThrow::finalize(Module* wasm) {
Expand All @@ -1489,8 +1405,6 @@ void ResumeThrow::finalize(Module* wasm) {
this->contType.getContinuation().type.getSignature();
type = contSig.results;
}

populateResumeThrowSentTypes(this, wasm);
}

void StackSwitch::finalize(Module* wasm) {
Expand Down