From e5e87fad266bdb49b2b1f2179c01568b83c0b308 Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Sun, 9 Nov 2025 05:45:05 +0800 Subject: [PATCH] [Stack Switching] Use move semantics for resume entries Add rvalue reference overload for pushResumeEntry and apply std::move throughout suspend/resume operations to eliminate unnecessary copies. --- src/wasm-interpreter.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 2b98c12af31..c5c1e25078d 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -511,6 +511,20 @@ class ExpressionRunner : public OverriddenVisitor { currContinuation->resumeInfo.push_back(entry); } + // Rvalue reference overload to avoid unnecessary copies when the entry + // is about to be destroyed. + void pushResumeEntry(Literals&& entry, const char* what) { + auto currContinuation = getCurrContinuationOrNull(); + if (!currContinuation) { + return; + } +#if WASM_INTERPRETER_DEBUG + std::cout << indent() << "push resume entry [" << what << "]: " << entry + << "\n"; +#endif + currContinuation->resumeInfo.push_back(std::move(entry)); + } + // Fetch an entry as we resume. Instructions call this as we rewind. Literals popResumeEntry(const char* what) { #if WASM_INTERPRETER_DEBUG @@ -518,7 +532,7 @@ class ExpressionRunner : public OverriddenVisitor { #endif auto currContinuation = getCurrContinuation(); assert(!currContinuation->resumeInfo.empty()); - auto entry = currContinuation->resumeInfo.back(); + auto entry = std::move(currContinuation->resumeInfo.back()); currContinuation->resumeInfo.pop_back(); #if WASM_INTERPRETER_DEBUG std::cout << indent() << " => " << entry << "\n"; @@ -618,8 +632,7 @@ class ExpressionRunner : public OverriddenVisitor { auto& values = valueStack.back(); auto num = values.size(); while (!values.empty()) { - // TODO: std::move, &elsewhere? - pushResumeEntry(values.back(), "child value"); + pushResumeEntry(std::move(values.back()), "child value"); values.pop_back(); } pushResumeEntry({Literal(int32_t(num))}, "num executed children"); @@ -687,7 +700,7 @@ class ExpressionRunner : public OverriddenVisitor { // in the block. entry.push_back(Literal(uint32_t(stack.size()))); entry.push_back(Literal(uint32_t(blockIndex))); - pushResumeEntry(entry, "block"); + pushResumeEntry(std::move(entry), "block"); }; Index blockIndex = 0; if (isResuming()) { @@ -4779,7 +4792,7 @@ class ModuleRunnerBase : public ExpressionRunner { // callFunction() will read it. Then call into the other module. This // sets this up as if we called into the proper module in the first // place. - self()->pushResumeEntry(entry, "function-target"); + self()->pushResumeEntry(std::move(entry), "function-target"); return data->doCall(arguments); } @@ -4843,7 +4856,7 @@ class ModuleRunnerBase : public ExpressionRunner { if (flow.suspendTag) { // Save the local state. for (auto& local : scope.locals) { - self()->pushResumeEntry(local, "function-local"); + self()->pushResumeEntry(std::move(local), "function-local"); } // Save the function we called (in the case of a return call, this is