Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
("i64.extend32_s", "makeUnary(UnaryOp::ExtendS32Int64)"),
# atomic instructions
("memory.atomic.notify", "makeAtomicNotify()"),
("struct.wait", "makeStructWait()"),
("memory.atomic.wait32", "makeAtomicWait(Type::i32)"),
("memory.atomic.wait64", "makeAtomicWait(Type::i64)"),
("atomic.fence", "makeAtomicFence()"),
Expand Down
6 changes: 6 additions & 0 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5400,6 +5400,12 @@ switch (buf[0]) {
return Ok{};
}
goto parse_error;
case 'w':
if (op == "struct.wait"sv) {
CHECK_ERR(makeStructWait(ctx, pos, annotations));
return Ok{};
}
goto parse_error;
default: goto parse_error;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/interpreter/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
Flow visitResume(Resume* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitResumeThrow(ResumeThrow* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitStackSwitch(StackSwitch* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitStructWait(StructWait* curr) { WASM_UNREACHABLE("TODO"); }
};

} // anonymous namespace
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ void ReFinalize::visitStructGet(StructGet* curr) { curr->finalize(); }
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::visitArrayNew(ArrayNew* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewData(ArrayNewData* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); }
Expand Down
15 changes: 15 additions & 0 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,21 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
note(&curr->replacement, type);
}

void visitStructWait(StructWait* curr,
std::optional<HeapType> ht = std::nullopt) {
if (!ht) {
if (!curr->ref->type.isStruct()) {
self().noteUnknown();
return;
}
ht = curr->structType;
}

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

void visitArrayNew(ArrayNew* curr) {
if (!curr->isWithDefault()) {
if (!curr->type.isRef()) {
Expand Down
4 changes: 4 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return AtomicCost + visit(curr->ptr) + visit(curr->expected) +
visit(curr->timeout);
}
CostType visitStructWait(StructWait* curr) {
return AtomicCost + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->expected) + visit(curr->timeout);
}
CostType visitAtomicNotify(AtomicNotify* curr) {
return AtomicCost + visit(curr->ptr) + visit(curr->notifyCount);
}
Expand Down
21 changes: 21 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,27 @@ class EffectAnalyzer {
assert(curr->order != MemoryOrder::Unordered);
parent.isAtomic = true;
}
void visitStructWait(StructWait* curr) {
parent.isAtomic = true;
parent.mayNotReturn = true;
parent.implicitTrap = true;

if (curr->ref->type == Type::unreachable) {
return;
}

// If the ref isn't `unreachable`, then the field must exist and be a
// packed waitqueue due to validation.
if (curr->ref->type.isStruct() &&
curr->index <
curr->ref->type.getHeapType().getStruct().fields.size() &&
curr->ref->type.getHeapType()
.getStruct()
.fields.at(curr->index)
.mutable_ == Mutable) {
parent.readsMutableStruct = true;
}
}
void visitRefAs(RefAs* curr) {
if (curr->op == AnyConvertExtern || curr->op == ExternConvertAny) {
// These conversions are infallible.
Expand Down
4 changes: 4 additions & 0 deletions src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@ struct CodeScanner : PostWalker<CodeScanner> {
void visitStructSet(StructSet* curr) { info.note(curr->ref->type); }
void visitArrayGet(ArrayGet* curr) { info.note(curr->ref->type); }
void visitArraySet(ArraySet* curr) { info.note(curr->ref->type); }
void visitStructWait(StructWait* curr) {
info.note(curr->ref->type);
info.note(curr->structType);
}
void visitContBind(ContBind* curr) {
info.note(curr->cont->type);
info.note(curr->type);
Expand Down
1 change: 1 addition & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,7 @@ struct InfoCollector
// TODO: optimize when possible
addRoot(curr);
}
void visitStructWait(StructWait* curr) { addRoot(curr); }

void visitFunction(Function* func) {
// Functions with a result can flow a value out from their body.
Expand Down
1 change: 1 addition & 0 deletions src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
type.isRef() ? Type(HeapType::eq, Nullable) : type);
self()->noteSubtype(curr->replacement, type);
}
void visitStructWait(StructWait* curr) {}
void visitRefAs(RefAs* curr) {
switch (curr->op) {
case RefAsNonNull:
Expand Down
13 changes: 13 additions & 0 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,12 @@ struct NullInstrParserCtx {
makeStackSwitch(Index, const std::vector<Annotation>&, HeapTypeT, TagIdxT) {
return Ok{};
}

template<typename HeapTypeT>
Result<>
makeStructWait(Index, const std::vector<Annotation>&, HeapTypeT, FieldIdxT) {
return Ok{};
}
};

struct NullCtx : NullTypeParserCtx, NullInstrParserCtx {
Expand Down Expand Up @@ -2947,6 +2953,13 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
Name tag) {
return withLoc(pos, irBuilder.makeStackSwitch(type, tag));
}

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

} // namespace wasm::WATParser
Expand Down
11 changes: 11 additions & 0 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2840,6 +2840,17 @@ Result<> makeStackSwitch(Ctx& ctx,
return ctx.makeStackSwitch(pos, annotations, *type, *tag);
}

template<typename Ctx>
Result<> makeStructWait(Ctx& ctx,
Index pos,
const std::vector<Annotation>& annotations) {
auto type = typeidx(ctx);
CHECK_ERR(type);
auto field = fieldidx(ctx, *type);
CHECK_ERR(field);
return ctx.makeStructWait(pos, annotations, *type, *field);
}

// =======
// Modules
// =======
Expand Down
13 changes: 13 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
visitExpression(curr);
}
}
void visitStructWait(StructWait* curr) {
if (!maybePrintUnreachableReplacement(curr, curr->type)) {
visitExpression(curr);
}
}

// Module-level visitors
void handleSignature(Function* curr, bool printImplicitNames = false);
Expand Down Expand Up @@ -2658,6 +2663,14 @@ struct PrintExpressionContents
o << ' ';
curr->tag.print(o);
}

void visitStructWait(StructWait* curr) {
printMedium(o, "struct.wait");
o << ' ';
printHeapTypeName(curr->structType);
o << ' ';
o << curr->index;
}
};

void PrintSExpression::setModule(Module* module) {
Expand Down
1 change: 1 addition & 0 deletions src/passes/TypeGeneralizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ struct TransferFn : OverriddenVisitor<TransferFn> {
void visitResume(Resume* curr) { WASM_UNREACHABLE("TODO"); }
void visitResumeThrow(ResumeThrow* curr) { WASM_UNREACHABLE("TODO"); }
void visitStackSwitch(StackSwitch* curr) { WASM_UNREACHABLE("TODO"); }
void visitStructWait(StructWait* curr) { WASM_UNREACHABLE("TODO"); }
};

struct TypeGeneralizing : WalkerPass<PostWalker<TypeGeneralizing>> {
Expand Down
4 changes: 4 additions & 0 deletions src/passes/TypeSSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ struct Analyzer

// We don't mind if we cannot compute a constraint due to unreachability.
void noteUnknown() {}

void visitStructWait(StructWait* curr) {
// Nothing exact here.
}
} typer(*this);
typer.visit(curr);
}
Expand Down
8 changes: 5 additions & 3 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ enum ASTNodes {
I64AtomicWait = 0x02,
AtomicFence = 0x03,
Pause = 0x04,
StructWait = 0x05,

I32AtomicLoad = 0x10,
I64AtomicLoad = 0x11,
Expand Down Expand Up @@ -1252,9 +1253,10 @@ enum ASTNodes {
Resume = 0xe3,
ResumeThrow = 0xe4,
ResumeThrowRef = 0xe5,
Switch = 0xe6, // NOTE(dhil): the internal class is known as
// StackSwitch to avoid conflict with the existing
// 'switch table'.
Switch = 0xe6, // NOTE(dhil): the internal class is known as
// StackSwitch to avoid conflict with the existing
// 'switch table'.

OnLabel = 0x00, // (on $tag $label)
OnSwitch = 0x01 // (on $tag switch)
};
Expand Down
15 changes: 15 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,21 @@ class Builder {
return ret;
}

StructWait* makeStructWait(HeapType structType,
Index index,
Expression* ref,
Expression* expected,
Expression* timeout) {
auto* ret = wasm.allocator.alloc<StructWait>();
ret->structType = structType;
ret->index = index;
ret->ref = ref;
ret->expected = expected;
ret->timeout = timeout;
ret->finalize();
return ret;
}

// Additional helpers

Drop* makeDrop(Expression* value) {
Expand Down
8 changes: 8 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,14 @@ DELEGATE_FIELD_CHILD_VECTOR(StackSwitch, operands)
DELEGATE_FIELD_NAME_KIND(StackSwitch, tag, ModuleItemKind::Tag)
DELEGATE_FIELD_CASE_END(StackSwitch)

DELEGATE_FIELD_CASE_START(StructWait)
DELEGATE_FIELD_CHILD(StructWait, timeout)
DELEGATE_FIELD_CHILD(StructWait, expected)
DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(StructWait, ref)
DELEGATE_FIELD_INT(StructWait, index)
DELEGATE_FIELD_HEAPTYPE(StructWait, structType)
DELEGATE_FIELD_CASE_END(StructWait)


DELEGATE_FIELD_MAIN_END

Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,6 @@ DELEGATE(Suspend);
DELEGATE(Resume);
DELEGATE(ResumeThrow);
DELEGATE(StackSwitch);
DELEGATE(StructWait);

#undef DELEGATE
5 changes: 5 additions & 0 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2932,6 +2932,7 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
Flow visitResume(Resume* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitResumeThrow(ResumeThrow* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitStackSwitch(StackSwitch* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitStructWait(StructWait* curr) { return Flow(NONCONSTANT_FLOW); }

void trap(std::string_view why) override { throw NonconstantException(); }

Expand Down Expand Up @@ -4918,6 +4919,10 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
Flow visitResume(Resume* curr) { return doResume(curr); }
Flow visitResumeThrow(ResumeThrow* curr) { return doResume(curr); }
Flow visitStackSwitch(StackSwitch* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitStructWait(StructWait* curr) {
WASM_UNREACHABLE("struct.wait not implemented");
return Flow();
}

void trap(std::string_view why) override {
// Traps break all current continuations - they will never be resumable.
Expand Down
1 change: 1 addition & 0 deletions src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
return makeResumeThrow(ct, Name(), tags, labels);
}
Result<> makeStackSwitch(HeapType ct, Name tag);
Result<> makeStructWait(HeapType type, Index index);

// Private functions that must be public for technical reasons.
Result<> visitExpression(Expression*);
Expand Down
2 changes: 1 addition & 1 deletion src/wasm-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class HeapType {
// stack, `HeapType` is used to describe the structures that reference types
// refer to. HeapTypes are canonicalized and interned exactly like Types and
// should also be passed by value.
uintptr_t id;
uintptr_t id = 0;

static constexpr int TypeBits = 2;
static constexpr int UsedBits = TypeBits + 1;
Expand Down
15 changes: 15 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ class Expression {
ResumeThrowId,
// Id for the stack switching `switch`
StackSwitchId,
StructWaitId,
NumExpressionIds
};
Id _id;
Expand Down Expand Up @@ -2155,6 +2156,20 @@ class StackSwitch : public SpecificExpression<Expression::StackSwitchId> {
void finalize();
};

class StructWait : public SpecificExpression<Expression::StructWaitId> {
public:
StructWait() = default;
StructWait(MixedArena& allocator) : StructWait() {}

Expression* ref = nullptr;
Expression* expected = nullptr;
Expression* timeout = nullptr;
HeapType structType;
Index index = -1;

void finalize();
};

// Globals

struct Named {
Expand Down
5 changes: 5 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3913,6 +3913,11 @@ Result<> WasmBinaryReader::readInst() {
auto type = getIndexedHeapType();
return builder.makeArrayCmpxchg(type, order);
}
case BinaryConsts::StructWait: {
auto structType = getIndexedHeapType();
auto index = getU32LEB();
return builder.makeStructWait(structType, index);
}
}
return Err{"unknown atomic operation " + std::to_string(op)};
}
Expand Down
Loading
Loading