Skip to content

Commit

Permalink
[Typed continuations] resume instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
frank-emrich committed Nov 5, 2023
1 parent 4fba26a commit f9ab9d4
Show file tree
Hide file tree
Showing 25 changed files with 373 additions and 0 deletions.
2 changes: 2 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@
# Typed function references instructions
("call_ref", "makeCallRef(s, /*isReturn=*/false)"),
("return_call_ref", "makeCallRef(s, /*isReturn=*/true)"),
# Typed continuations instructions
("resume", "makeResume(s)"),
# GC
("i31.new", "makeRefI31(s)"), # deprecated
("ref.i31", "makeRefI31(s)"),
Expand Down
9 changes: 9 additions & 0 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3004,6 +3004,9 @@ switch (buf[0]) {
default: goto parse_error;
}
}
case 's':
if (op == "resume"sv) { return makeResume(s); }
goto parse_error;
case 't': {
switch (buf[3]) {
case 'h':
Expand Down Expand Up @@ -8110,6 +8113,12 @@ switch (buf[0]) {
default: goto parse_error;
}
}
case 's':
if (op == "resume"sv) {
CHECK_ERR(makeResume(ctx, pos));
return Ok{};
}
goto parse_error;
case 't': {
switch (buf[3]) {
case 'h':
Expand Down
2 changes: 2 additions & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ void ReFinalize::visitStringSliceIter(StringSliceIter* curr) {
curr->finalize();
}

void ReFinalize::visitResume(Resume* curr) { curr->finalize(); }

void ReFinalize::visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
void ReFinalize::visitTable(Table* curr) { WASM_UNREACHABLE("unimp"); }
Expand Down
22 changes: 22 additions & 0 deletions src/ir/branch-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ 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* res = expr->dynCast<Resume>()) {
// FIXME(frank-emrich) For each of the (tag $t $b) entries for the resume
// instruction, we could determine the types of the values passed to block
// $b by looking up the signature of tag $t in the module, plus taking the
// type of the resumed continuation into account (the latter type is
// stored in the Resume node directly).
//
// However, we do not have access to that information at this point. We
// could get it from the Module (to look up the tag), but this would
// require additional plumbing at all the use sites of this function, such
// as users of BranchSeeker, which is in turn used by functions such as
// Block::finalize(). Plumbing the module through to that point would
// require chancing the re-finalisation code, for example.
//
// We could also store this information in the Resume node itself, but
// that would mean storing the signature of all the Tags that we have a
// handle clause for.
func(name, Type::none);
} else {
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow
}
Expand All @@ -97,6 +115,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* res = expr->dynCast<Resume>()) {
// FIXME(frank-emrich) We can't really determine the values being sent
// here because they come from suspend instructions elsewhere. Is that a
// problem?
} else {
assert(expr->is<Try>() || expr->is<Rethrow>()); // delegate or rethrow
}
Expand Down
5 changes: 5 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,11 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 8 + visit(curr->ref) + visit(curr->num);
}

CostType visitResume(Resume* curr) {
// Inspired by indirect calls, but twice the cost.
return 12 + visit(curr->cont);
}

private:
CostType nullCheckCost(Expression* ref) {
// A nullable type requires a bounds check in most VMs.
Expand Down
14 changes: 14 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,20 @@ class EffectAnalyzer {
// traps when ref is null.
parent.implicitTrap = true;
}

void visitResume(Resume* curr) {
// This acts as a kitchen sink effect.
parent.calls = true;

// FIXME(frank-emrich) We should probably set parent.trap or
// parent.implicitTrap, because the resume instruction itself may trap:
// The continuation reference is nullable, and we trap if it is indeed
// null.

if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
parent.throws_ = true;
}
}
};

public:
Expand Down
2 changes: 2 additions & 0 deletions src/ir/module-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ struct CodeScanner
counts.include(get->type);
} else if (auto* set = curr->dynCast<ArraySet>()) {
counts.note(set->ref->type);
} else if (auto* resume = curr->dynCast<Resume>()) {
counts.note(resume->contType);
} else if (Properties::isControlFlowStructure(curr)) {
counts.noteControlFlow(Signature(Type::none, curr->type));
}
Expand Down
5 changes: 5 additions & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,11 @@ struct InfoCollector

void visitReturn(Return* curr) { addResult(curr->value); }

void visitResume(Resume* curr) {
// TODO: optimize when possible
addRoot(curr);
}

void visitFunction(Function* func) {
// Functions with a result can flow a value out from their body.
addResult(func->body);
Expand Down
5 changes: 5 additions & 0 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ Result<> makeStringIterMove(Ctx&, Index, StringIterMoveOp op);
template<typename Ctx>
Result<> makeStringSliceWTF(Ctx&, Index, StringSliceWTFOp op);
template<typename Ctx> Result<> makeStringSliceIter(Ctx&, Index);
template<typename Ctx> Result<> makeResume(Ctx&, Index);

// Modules
template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx);
Expand Down Expand Up @@ -1477,6 +1478,10 @@ template<typename Ctx> Result<> makeStringSliceIter(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}

template<typename Ctx> Result<> makeResume(Ctx& ctx, Index pos) {
return ctx.in.err("unimplemented instruction");
}

// =======
// Modules
// =======
Expand Down
31 changes: 31 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
void visitIf(If* curr);
void visitLoop(Loop* curr);
void visitTry(Try* curr);
void visitResume(Resume* curr);
void maybePrintUnreachableReplacement(Expression* curr, Type type);
void maybePrintUnreachableOrNullReplacement(Expression* curr, Type type);
void visitCallRef(CallRef* curr) {
Expand Down Expand Up @@ -2384,6 +2385,7 @@ struct PrintExpressionContents
void visitStringSliceIter(StringSliceIter* curr) {
printMedium(o, "stringview_iter.slice");
}
void visitResume(Resume* curr) { printMedium(o, "resume"); }
};

void PrintSExpression::setModule(Module* module) {
Expand Down Expand Up @@ -2711,6 +2713,35 @@ void PrintSExpression::visitTry(Try* curr) {
}
}

void PrintSExpression::visitResume(Resume* curr) {
controlFlowDepth++;
o << '(';
printExpressionContents(curr);
o << ' ';
printHeapType(curr->contType);
incIndent();

for (size_t i = 0; i < curr->handlerTags.size(); i++) {
doIndent(o, indent);

o << '(';
printMedium(o, "tag ");
printName(curr->handlerTags[i], o);
o << " ";
printName(curr->handlerBlocks[i], o);
o << ")\n";
}

for (size_t i = 0; i < curr->operands.size(); i++) {
printFullLine(curr->operands[i]);
}

printFullLine(curr->cont);

controlFlowDepth--;
decIndent();
}

void PrintSExpression::maybePrintUnreachableReplacement(Expression* curr,
Type type) {
// See the parallel function
Expand Down
6 changes: 6 additions & 0 deletions src/passes/Unsubtyping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,12 @@ struct Unsubtyping
void visitStringIterMove(StringIterMove* curr) {}
void visitStringSliceWTF(StringSliceWTF* curr) {}
void visitStringSliceIter(StringSliceIter* curr) {}

void visitResume(Resume* curr) {
// TODO Implement this by exposing the subtyping relations that the
// validator expects to hold, once validation of resume is implemented
WASM_UNREACHABLE("not implemented");
}
};

} // anonymous namespace
Expand Down
5 changes: 5 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,10 @@ enum ASTNodes {
StringEncodeLossyUTF8Array = 0xb6,
StringEncodeWTF8Array = 0xb7,
StringNewUTF8ArrayTry = 0xb8,

// typed continuation opcodes
Resume = 0xe3,

};

enum MemoryAccess {
Expand Down Expand Up @@ -1893,6 +1897,7 @@ class WasmBinaryReader {
void visitCallRef(CallRef* curr);
void visitRefAsCast(RefCast* curr, uint32_t code);
void visitRefAs(RefAs* curr, uint8_t code);
void visitResume(Resume* curr);

[[noreturn]] void throwError(std::string text);

Expand Down
15 changes: 15 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,21 @@ class Builder {
return ret;
}

Resume* makeResume(HeapType contType,
const std::vector<Name>& handlerTags,
const std::vector<Name>& handlerBlocks,
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->operands.set(operands);
ret->cont = cont;
ret->finalize();
return ret;
}

// Additional helpers

Drop* makeDrop(Expression* value) {
Expand Down
11 changes: 11 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,17 @@ switch (DELEGATE_ID) {
DELEGATE_END(StringSliceIter);
break;
}

case Expression::Id::ResumeId: {
DELEGATE_START(Resume);
DELEGATE_FIELD_CHILD(Resume, cont);
DELEGATE_FIELD_CHILD_VECTOR(Resume, operands);
DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(Resume, handlerBlocks);
DELEGATE_FIELD_NAME_KIND_VECTOR(Resume, handlerTags, ModuleItemKind::Tag);
DELEGATE_FIELD_HEAPTYPE(Resume, contType);
DELEGATE_END(Resume);
break;
}
}

#undef DELEGATE_ID
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@ DELEGATE(StringIterNext);
DELEGATE(StringIterMove);
DELEGATE(StringSliceWTF);
DELEGATE(StringSliceIter);
DELEGATE(Resume);

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

void trap(const char* why) override { throw NonconstantException(); }

Expand Down Expand Up @@ -3857,6 +3858,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
multiValues.pop_back();
return ret;
}
Flow visitResume(Resume* curr) { return Flow(NONCONSTANT_FLOW); }

void trap(const char* why) override { externalInterface->trap(why); }

Expand Down
1 change: 1 addition & 0 deletions src/wasm-s-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ class SExpressionWasmBuilder {
Expression* makeStringIterMove(Element& s, StringIterMoveOp op);
Expression* makeStringSliceWTF(Element& s, StringSliceWTFOp op);
Expression* makeStringSliceIter(Element& s);
Expression* makeResume(Element& s);

// Helper functions
Type parseBlockType(Element& s, Index& i);
Expand Down
16 changes: 16 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ class Expression {
StringIterMoveId,
StringSliceWTFId,
StringSliceIterId,
ResumeId,
NumExpressionIds
};
Id _id;
Expand Down Expand Up @@ -1920,6 +1921,21 @@ class StringSliceIter
void finalize();
};

class Resume : public SpecificExpression<Expression::ResumeId> {
public:
Resume(MixedArena& allocator)
: handlerTags(allocator), handlerBlocks(allocator), operands(allocator) {}

HeapType contType;
ArenaVector<Name> handlerTags;
ArenaVector<Name> handlerBlocks;

ExpressionList operands;
Expression* cont;

void finalize();
};

// Globals

struct Named {
Expand Down
Loading

0 comments on commit f9ab9d4

Please sign in to comment.