Skip to content

[DO NOT LAND] Experiment with using pops in the current interpreter #7762

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

Draft
wants to merge 39 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
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
Prev Previous commit
Next Next commit
SIMPL?
  • Loading branch information
kripken committed Jul 25, 2025
commit a823f1447e09c2a19c515fd1d42aacc1c4d2bbfe
124 changes: 64 additions & 60 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {

// Get a child value. This returns values in the natural order, the same as in
// the wat and in wasm.h.
Flow getChild() {
Literals getChild() {
assert(!visitValues.empty());
auto ret = visitValues.back();
#if WASM_INTERPRETER_DEBUG
Expand All @@ -220,6 +220,17 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
return ret;
}

// Get a single child value, returning a Literal rather than Literals.
Literal getSingleChild() {
assert(!visitValues.empty());
auto ret = visitValues.back()[0];
#if WASM_INTERPRETER_DEBUG
std::cout << indent() << "getting single child " << ret << '\n';
#endif
visitValues.pop_back();
return ret;
}

public:
ExpressionRunner(Module* module = nullptr,
Index maxDepth = NO_LIMIT,
Expand Down Expand Up @@ -369,14 +380,12 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
}
}
Flow visitBreak(Break* curr) {
bool condition = true;
Flow flow;
if (curr->value) {
flow = getChild();
}
if (curr->condition) {
Flow conditionFlow = getChild();
condition = conditionFlow.getSingleValue().getInteger() != 0;
auto condition = getSingleChild().getInteger() != 0;
if (!condition) {
return flow;
}
Expand Down Expand Up @@ -1663,18 +1672,17 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
if (curr->isWithDefault()) {
data[i] = Literal::makeZero(field.type);
} else {
auto value = getChild();
data[i] = truncateForPacking(value.getSingleValue(), field);
data[i] = truncateForPacking(getSingleChild(), field);
}
}
if (!curr->desc) {
return makeGCData(std::move(data), curr->type);
}
auto desc = getChild();
if (desc.getSingleValue().isNull()) {
auto desc = getSingleChild();
if (desc.isNull()) {
trap("null descriptor");
}
return makeGCData(std::move(data), curr->type, desc.getSingleValue());
return makeGCData(std::move(data), curr->type, desc);
}
Flow visitStructGet(StructGet* curr) {
Flow ref = getChild();
Expand Down Expand Up @@ -1754,18 +1762,18 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
static const Index DataLimit = (1 << 30) / sizeof(Literal);

Flow visitArrayNew(ArrayNew* curr) {
Flow init;
Literal init;
if (!curr->isWithDefault()) {
init = getChild();
init = getSingleChild();
}
auto size = getChild();
auto size = getSingleChild();
// If we are unreachable then we cannot proceed to compute the heap type,
// below, as there isn't one. But if we are unreachable then we should not
// get here, as the child would break in visit().
assert(curr->type != Type::unreachable);
auto heapType = curr->type.getHeapType();
const auto& element = heapType.getArray().element;
Index num = size.getSingleValue().geti32();
Index num = size.geti32();
if (num >= DataLimit) {
hostLimit("allocation failure");
}
Expand All @@ -1777,7 +1785,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
}
} else {
auto field = curr->type.getHeapType().getArray().element;
auto value = truncateForPacking(init.getSingleValue(), field);
auto value = truncateForPacking(init, field);
for (Index i = 0; i < num; i++) {
data[i] = value;
}
Expand All @@ -1799,8 +1807,8 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
auto field = heapType.getArray().element;
Literals data(num);
for (Index i = 0; i < num; i++) {
auto value = getChild();
data[i] = truncateForPacking(value.getSingleValue(), field);
auto value = getSingleChild();
data[i] = truncateForPacking(value, field);
}
return makeGCData(std::move(data), curr->type);
}
Expand Down Expand Up @@ -2324,14 +2332,12 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
// constant value set, if any, and see if there is a value flowing through
// a tee.
auto setFlow = self()->getChild();
if (!setFlow.breaking()) {
setLocalValue(curr->index, setFlow.values);
if (curr->type.isConcrete()) {
assert(curr->isTee());
return setFlow;
}
return Flow();
setLocalValue(curr->index, setFlow);
if (curr->type.isConcrete()) {
assert(curr->isTee());
return setFlow;
}
return Flow();
}
return Flow(NONCONSTANT_FLOW);
}
Expand All @@ -2357,10 +2363,8 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
// constant value set, if any, for subsequent gets.
assert(this->module->getGlobal(curr->name)->mutable_);
auto setFlow = self()->getChild();
if (!setFlow.breaking()) {
setGlobalValue(curr->name, setFlow.values);
return Flow();
}
setGlobalValue(curr->name, setFlow);
return Flow();
}
return Flow(NONCONSTANT_FLOW);
}
Expand Down Expand Up @@ -3338,30 +3342,30 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
}

Flow visitAtomicRMW(AtomicRMW* curr) {
Flow ptr = self()->getChild();
auto value = self()->getChild();
auto ptr = self()->getSingleChild();
auto value = self()->getSingleChild();
auto info = getMemoryInstanceInfo(curr->memory);
auto memorySize = info.instance->getMemorySize(info.name);
auto addr =
info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize);
info.instance->getFinalAddress(curr, ptr, memorySize);
auto loaded = info.instance->doAtomicLoad(
addr, curr->bytes, curr->type, info.name, memorySize);
auto computed = value.getSingleValue();
Literal computed;
switch (curr->op) {
case RMWAdd:
computed = loaded.add(computed);
computed = loaded.add(value);
break;
case RMWSub:
computed = loaded.sub(computed);
computed = loaded.sub(value);
break;
case RMWAnd:
computed = loaded.and_(computed);
computed = loaded.and_(value);
break;
case RMWOr:
computed = loaded.or_(computed);
computed = loaded.or_(value);
break;
case RMWXor:
computed = loaded.xor_(computed);
computed = loaded.xor_(value);
break;
case RMWXchg:
break;
Expand All @@ -3371,53 +3375,53 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return loaded;
}
Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
Flow ptr = self()->getChild();
auto expected = self()->getChild();
auto replacement = self()->getChild();
auto ptr = self()->getSingleChild();
auto expected = self()->getSingleChild();
auto replacement = self()->getSingleChild();
auto info = getMemoryInstanceInfo(curr->memory);
auto memorySize = info.instance->getMemorySize(info.name);
auto addr =
info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize);
expected = Flow(wrapToSmallerSize(expected.getSingleValue(), curr->bytes));
info.instance->getFinalAddress(curr, ptr, memorySize);
expected = wrapToSmallerSize(expected, curr->bytes);
auto loaded = info.instance->doAtomicLoad(
addr, curr->bytes, curr->type, info.name, memorySize);
if (loaded == expected.getSingleValue()) {
if (loaded == expected) {
info.instance->doAtomicStore(
addr, curr->bytes, replacement.getSingleValue(), info.name, memorySize);
addr, curr->bytes, replacement, info.name, memorySize);
}
return loaded;
}
Flow visitAtomicWait(AtomicWait* curr) {
Flow ptr = self()->getChild();
auto expected = self()->getChild();
auto timeout = self()->getChild();
auto ptr = self()->getSingleChild();
auto expected = self()->getSingleChild();
auto timeout = self()->getSingleChild();
auto bytes = curr->expectedType.getByteSize();
auto info = getMemoryInstanceInfo(curr->memory);
auto memorySize = info.instance->getMemorySize(info.name);
auto addr = info.instance->getFinalAddress(
curr, ptr.getSingleValue(), bytes, memorySize);
curr, ptr, bytes, memorySize);
auto loaded = info.instance->doAtomicLoad(
addr, bytes, curr->expectedType, info.name, memorySize);
if (loaded != expected.getSingleValue()) {
if (loaded != expected) {
return Literal(int32_t(1)); // not equal
}
// TODO: Add threads support. For now, report a host limit here, as there
// are no other threads that can wake us up. Without such threads,
// we'd hang if there is no timeout, and even if there is a timeout
// then we can hang for a long time if it is in a loop. The only
// timeout value we allow here for now is 0.
if (timeout.getSingleValue().getInteger() != 0) {
if (timeout.getInteger() != 0) {
hostLimit("threads support");
}
return Literal(int32_t(2)); // Timed out
}
Flow visitAtomicNotify(AtomicNotify* curr) {
Flow ptr = self()->getChild();
auto count = self()->getChild();
auto ptr = self()->getSingleChild();
auto count = self()->getSingleChild();
auto info = getMemoryInstanceInfo(curr->memory);
auto memorySize = info.instance->getMemorySize(info.name);
auto addr =
info.instance->getFinalAddress(curr, ptr.getSingleValue(), 4, memorySize);
info.instance->getFinalAddress(curr, ptr, 4, memorySize);
// Just check TODO actual threads support
info.instance->checkAtomicAddress(addr, 4, memorySize);
return Literal(int32_t(0)); // none woken up
Expand Down Expand Up @@ -3752,11 +3756,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return {};
}
Flow visitArrayNewData(ArrayNewData* curr) {
auto offsetFlow = self()->getChild();
auto sizeFlow = self()->getChild();
auto offsetFlow = self()->getSingleChild();
auto sizeFlow = self()->getSingleChild();

uint64_t offset = offsetFlow.getSingleValue().getUnsigned();
uint64_t size = sizeFlow.getSingleValue().getUnsigned();
uint64_t offset = offsetFlow.getUnsigned();
uint64_t size = sizeFlow.getUnsigned();

auto heapType = curr->type.getHeapType();
const auto& element = heapType.getArray().element;
Expand Down Expand Up @@ -3786,11 +3790,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
return self()->makeGCData(std::move(contents), curr->type);
}
Flow visitArrayNewElem(ArrayNewElem* curr) {
auto offsetFlow = self()->getChild();
auto sizeFlow = self()->getChild();
auto offsetFlow = self()->getSingleChild();
auto sizeFlow = self()->getSingleChild();

uint64_t offset = offsetFlow.getSingleValue().getUnsigned();
uint64_t size = sizeFlow.getSingleValue().getUnsigned();
uint64_t offset = offsetFlow.getUnsigned();
uint64_t size = sizeFlow.getUnsigned();

Literals contents;

Expand Down