Skip to content
Draft
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
3 changes: 2 additions & 1 deletion scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@
# atomic instructions
("memory.atomic.notify", "makeAtomicNotify()"),
("struct.wait", "makeStructWait()"),
("struct.notify", "makeStructNotify()"),
("waitqueue.new", "makeWaitqueueNew()"),
("waitqueue.notify", "makeWaitqueueNotify()"),
("memory.atomic.wait32", "makeAtomicWait(Type::i32)"),
("memory.atomic.wait64", "makeAtomicWait(Type::i64)"),
("atomic.fence", "makeAtomicFence()"),
Expand Down
4 changes: 4 additions & 0 deletions src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ BinaryenLiteral toBinaryenLiteral(Literal x) {
case HeapType::exn:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::waitqueue:
case HeapType::nowaitqueue:
WASM_UNREACHABLE("TODO: string literals");
case HeapType::none:
case HeapType::noext:
Expand Down Expand Up @@ -146,6 +148,8 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) {
case HeapType::exn:
WASM_UNREACHABLE("invalid type");
case HeapType::string:
case HeapType::waitqueue:
case HeapType::nowaitqueue:
WASM_UNREACHABLE("TODO: string literals");
case HeapType::none:
case HeapType::noext:
Expand Down
78 changes: 42 additions & 36 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5433,52 +5433,41 @@ switch (buf[0]) {
}
}
case 'n': {
switch (buf[8]) {
case 'e': {
switch (buf[10]) {
case '\0':
if (op == "struct.new"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, false, false));
return Ok{};
}
goto parse_error;
case '_': {
switch (buf[13]) {
case 'f': {
switch (buf[18]) {
case '\0':
if (op == "struct.new_default"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, true, false));
return Ok{};
}
goto parse_error;
case '_':
if (op == "struct.new_default_desc"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, true, true));
return Ok{};
}
goto parse_error;
default: goto parse_error;
switch (buf[10]) {
case '\0':
if (op == "struct.new"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, false, false));
return Ok{};
}
goto parse_error;
case '_': {
switch (buf[13]) {
case 'f': {
switch (buf[18]) {
case '\0':
if (op == "struct.new_default"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, true, false));
return Ok{};
}
}
case 's':
if (op == "struct.new_desc"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, false, true));
goto parse_error;
case '_':
if (op == "struct.new_default_desc"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, true, true));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
case 's':
if (op == "struct.new_desc"sv) {
CHECK_ERR(makeStructNew(ctx, pos, annotations, false, true));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
case 'o':
if (op == "struct.notify"sv) {
CHECK_ERR(makeStructNotify(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
Expand Down Expand Up @@ -5878,6 +5867,23 @@ switch (buf[0]) {
default: goto parse_error;
}
}
case 'w': {
switch (buf[11]) {
case 'e':
if (op == "waitqueue.new"sv) {
CHECK_ERR(makeWaitqueueNew(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
case 'o':
if (op == "waitqueue.notify"sv) {
CHECK_ERR(makeWaitqueueNotify(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
parse_error:
Expand Down
3 changes: 2 additions & 1 deletion src/interpreter/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
Flow visitStructRMW(StructRMW* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitStructCmpxchg(StructCmpxchg* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitStructWait(StructWait* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitStructNotify(StructNotify* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitWaitqueueNew(WaitqueueNew* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitWaitqueueNotify(WaitqueueNotify* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayNew(ArrayNew* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayNewData(ArrayNewData* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayNewElem(ArrayNewElem* curr) { WASM_UNREACHABLE("TODO"); }
Expand Down
5 changes: 4 additions & 1 deletion src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,10 @@ void ReFinalize::visitStructSet(StructSet* curr) { curr->finalize(); }
void ReFinalize::visitStructRMW(StructRMW* curr) { curr->finalize(); }
void ReFinalize::visitStructCmpxchg(StructCmpxchg* curr) { curr->finalize(); }
void ReFinalize::visitStructWait(StructWait* curr) { curr->finalize(); }
void ReFinalize::visitStructNotify(StructNotify* curr) { curr->finalize(); }
void ReFinalize::visitWaitqueueNew(WaitqueueNew* curr) { curr->finalize(); }
void ReFinalize::visitWaitqueueNotify(WaitqueueNotify* curr) {
curr->finalize();
}
void ReFinalize::visitArrayNew(ArrayNew* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewData(ArrayNewData* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); }
Expand Down
14 changes: 4 additions & 10 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1037,21 +1037,15 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
}

note(&curr->ref, Type(*ht, Nullable));
note(&curr->waitqueue, Type(HeapType::waitqueue, Nullable));
note(&curr->expected, Type(Type::BasicType::i32));
note(&curr->timeout, Type(Type::BasicType::i64));
}

void visitStructNotify(StructNotify* curr,
std::optional<HeapType> ht = std::nullopt) {
if (!ht) {
if (!curr->ref->type.isStruct()) {
self().noteUnknown();
return;
}
ht = curr->ref->type.getHeapType();
}
void visitWaitqueueNew(WaitqueueNew* curr) {}

note(&curr->ref, Type(*ht, Nullable));
void visitWaitqueueNotify(WaitqueueNotify* curr) {
note(&curr->waitqueue, Type(HeapType::waitqueue, Nullable));
note(&curr->count, Type(Type::BasicType::i32));
}

Expand Down
8 changes: 5 additions & 3 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
}
CostType visitStructWait(StructWait* curr) {
return AtomicCost + nullCheckCost(curr->ref) + visit(curr->ref) +
nullCheckCost(curr->waitqueue) + visit(curr->waitqueue) +
visit(curr->expected) + visit(curr->timeout);
}
CostType visitStructNotify(StructNotify* curr) {
return AtomicCost + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->count);
CostType visitWaitqueueNew(WaitqueueNew* curr) { return 1; }
CostType visitWaitqueueNotify(WaitqueueNotify* curr) {
return AtomicCost + nullCheckCost(curr->waitqueue) +
visit(curr->waitqueue) + visit(curr->count);
}
CostType visitAtomicNotify(AtomicNotify* curr) {
return AtomicCost + visit(curr->ptr) + visit(curr->notifyCount);
Expand Down
16 changes: 8 additions & 8 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,9 @@ class EffectAnalyzer {
if (trapOnNull(curr->ref)) {
return;
}
if (trapOnNull(curr->waitqueue)) {
return;
}
// StructWait doesn't strictly write a struct, but it does modify the
// waiters list associated with the waitqueue field, which we can think
// of as a write.
Expand All @@ -1108,16 +1111,13 @@ class EffectAnalyzer {
// If the timeout is negative and no-one wakes us.
parent.mayNotReturn = true;
}
void visitStructNotify(StructNotify* curr) {
if (trapOnNull(curr->ref)) {
return;
}
// Non-shared notifies just return 0.
if (curr->ref->type.getHeapType().isShared()) {
void visitWaitqueueNew(WaitqueueNew* curr) {}
void visitWaitqueueNotify(WaitqueueNotify* curr) {
if (trapOnNull(curr->waitqueue)) {
return;
}
// AtomicNotify doesn't strictly write the struct, but it does
// modify the waiters list associated with the waitqueue field, which we
// AtomicNotify doesn't strictly write anything, but it does
// modify the waiters list associated with the waitqueue, which we
// can think of as a write.
parent.readsSharedMutableStruct = true;
parent.writesSharedStruct = true;
Expand Down
5 changes: 4 additions & 1 deletion src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,10 @@ struct CodeScanner : PostWalker<CodeScanner> {
void visitStructGet(StructGet* curr) { info.note(curr->ref->type); }
void visitStructSet(StructSet* curr) { info.note(curr->ref->type); }
void visitStructWait(StructWait* curr) { info.note(curr->ref->type); }
void visitStructNotify(StructNotify* curr) { info.note(curr->ref->type); }
void visitWaitqueueNew(WaitqueueNew* curr) { info.note(curr->type); }
void visitWaitqueueNotify(WaitqueueNotify* curr) {
info.note(curr->waitqueue->type);
}
void visitArrayGet(ArrayGet* curr) { info.note(curr->ref->type); }
void visitArraySet(ArraySet* curr) { info.note(curr->ref->type); }
void visitContBind(ContBind* curr) {
Expand Down
3 changes: 0 additions & 3 deletions src/ir/possible-constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ struct PossibleConstantValues {
value = val.and_(Literal(uint32_t(0xffff)));
}
break;
case Field::WaitQueue:
value = val;
break;
case Field::NotPacked:
WASM_UNREACHABLE("unexpected packed type");
break;
Expand Down
3 changes: 2 additions & 1 deletion src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,8 @@ struct InfoCollector
addRoot(curr);
}
void visitStructWait(StructWait* curr) { addRoot(curr); }
void visitStructNotify(StructNotify* curr) { addRoot(curr); }
void visitWaitqueueNew(WaitqueueNew* curr) { addRoot(curr); }
void visitWaitqueueNotify(WaitqueueNotify* curr) { addRoot(curr); }
// Array operations access the array's location, parallel to how structs work.
void visitArrayGet(ArrayGet* curr) {
if (!isRelevant(curr->ref)) {
Expand Down
5 changes: 4 additions & 1 deletion src/ir/properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ inline bool isSingleConstantExpression(const Expression* curr) {
}
}
return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>() ||
curr->is<StringConst>();
curr->is<StringConst>() || curr->is<WaitqueueNew>();
}

inline bool isConstantExpression(const Expression* curr) {
Expand Down Expand Up @@ -117,6 +117,9 @@ inline Literal getLiteral(const Expression* curr) {
return Literal(n->type);
} else if (auto* r = curr->dynCast<RefFunc>()) {
return Literal::makeFunc(r->func, r->type);
} else if (curr->is<WaitqueueNew>()) {
return Literal(
Type(HeapType(HeapType::waitqueue).getBasic(Shared), NonNullable));
} else if (auto* i = curr->dynCast<RefI31>()) {
if (auto* c = i->value->dynCast<Const>()) {
return Literal::makeI31(c->value.geti32(),
Expand Down
3 changes: 2 additions & 1 deletion src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,8 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
self()->noteSubtype(curr->replacement, type);
}
void visitStructWait(StructWait* curr) {}
void visitStructNotify(StructNotify* curr) {}
void visitWaitqueueNew(WaitqueueNew* curr) {}
void visitWaitqueueNotify(WaitqueueNotify* curr) {}
void visitArrayNew(ArrayNew* curr) {
if (!curr->type.isArray() || curr->isWithDefault()) {
return;
Expand Down
32 changes: 20 additions & 12 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ struct NullTypeParserCtx {
HeapTypeT makeNofuncType(Shareability) { return Ok{}; }
HeapTypeT makeNoexnType(Shareability) { return Ok{}; }
HeapTypeT makeNocontType(Shareability) { return Ok{}; }
HeapTypeT makeWaitqueueType(Shareability) { return Ok{}; }
HeapTypeT makeNowaitqueueType(Shareability) { return Ok{}; }

TypeT makeI32() { return Ok{}; }
TypeT makeI64() { return Ok{}; }
Expand Down Expand Up @@ -150,7 +152,6 @@ struct NullTypeParserCtx {

StorageT makeI8() { return Ok{}; }
StorageT makeI16() { return Ok{}; }
StorageT makeWaitQueue() { return Ok{}; }
StorageT makeStorageType(TypeT) { return Ok{}; }

FieldT makeFieldType(StorageT, Mutability) { return Ok{}; }
Expand Down Expand Up @@ -263,6 +264,12 @@ template<typename Ctx> struct TypeParserCtx {
HeapTypeT makeNocontType(Shareability share) {
return HeapTypes::nocont.getBasic(share);
}
HeapTypeT makeWaitqueueType(Shareability share) {
return HeapType(HeapType::waitqueue).getBasic(share);
}
HeapTypeT makeNowaitqueueType(Shareability share) {
return HeapType(HeapType::nowaitqueue).getBasic(share);
}

HeapTypeT makeExact(HeapTypeT type) {
type.exactness = Exact;
Expand Down Expand Up @@ -308,7 +315,6 @@ template<typename Ctx> struct TypeParserCtx {

StorageT makeI8() { return Field(Field::i8, Immutable); }
StorageT makeI16() { return Field(Field::i16, Immutable); }
StorageT makeWaitQueue() { return Field(Field::WaitQueue, Immutable); }
StorageT makeStorageType(TypeT type) { return Field(type, Immutable); }

FieldT makeFieldType(FieldT field, Mutability mutability) {
Expand Down Expand Up @@ -825,11 +831,10 @@ struct NullInstrParserCtx {
makeStructWait(Index, const std::vector<Annotation>&, HeapTypeT, FieldIdxT) {
return Ok{};
}
template<typename HeapTypeT>
Result<> makeStructNotify(Index,
const std::vector<Annotation>&,
HeapTypeT,
FieldIdxT) {
Result<> makeWaitqueueNew(Index, const std::vector<Annotation>&) {
return Ok{};
}
Result<> makeWaitqueueNotify(Index, const std::vector<Annotation>&) {
return Ok{};
}
template<typename HeapTypeT>
Expand Down Expand Up @@ -2804,11 +2809,14 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
return withLoc(pos, irBuilder.makeStructWait(type, field));
}

Result<> makeStructNotify(Index pos,
const std::vector<Annotation>& annotations,
HeapType type,
Index field) {
return withLoc(pos, irBuilder.makeStructNotify(type, field));
Result<> makeWaitqueueNew(Index pos,
const std::vector<Annotation>& annotations) {
return withLoc(pos, irBuilder.makeWaitqueueNew());
}

Result<> makeWaitqueueNotify(Index pos,
const std::vector<Annotation>& annotations) {
return withLoc(pos, irBuilder.makeWaitqueueNotify());
}

Result<> makeArrayNew(Index pos,
Expand Down
Loading
Loading