diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 35438d3e2e24..c7887b583ac3 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -1002,11 +1002,12 @@ auto Interpreter::StepStmt() -> Transition { todo.Push(arena->New( arena->New(arena, stmt->source_loc()))); todo.Push(arena->New(cast(*stmt).Body())); + auto continuation_stack = arena->New>>(); auto continuation_frame = arena->New("__continuation", scopes, todo); + continuation_stack->push_back(continuation_frame); Address continuation_address = - heap.AllocateValue(arena->New( - std::vector>({continuation_frame}))); + heap.AllocateValue(arena->New(continuation_stack)); // Store the continuation's address in the frame. continuation_frame->continuation = continuation_address; // Bind the continuation object to the continuation variable @@ -1031,11 +1032,11 @@ auto Interpreter::StepStmt() -> Transition { arena->New(stmt->source_loc()))); frame->todo.Push(ignore_result); // Push the continuation onto the current stack. - const std::vector>& continuation_vector = - cast(*act->results()[0]).Stack(); - for (auto frame_iter = continuation_vector.rbegin(); - frame_iter != continuation_vector.rend(); ++frame_iter) { - stack.Push(*frame_iter); + std::vector>& continuation_vector = + *cast(*act->results()[0]).Stack(); + while (!continuation_vector.empty()) { + stack.Push(continuation_vector.back()); + continuation_vector.pop_back(); } return ManualTransition{}; } @@ -1048,8 +1049,10 @@ auto Interpreter::StepStmt() -> Transition { paused.push_back(stack.Pop()); } while (paused.back()->continuation == std::nullopt); // Update the continuation with the paused stack. - heap.Write(*paused.back()->continuation, - arena->New(paused), stmt->source_loc()); + const auto& continuation = cast( + *heap.Read(*paused.back()->continuation, stmt->source_loc())); + CHECK(continuation.Stack()->empty()); + *continuation.Stack() = std::move(paused); return ManualTransition{}; } } diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 27d0c27c150d..092c4d8d5067 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -292,7 +292,7 @@ void Value::Print(llvm::raw_ostream& out) const { case Value::Kind::ContinuationValue: { out << "{"; llvm::ListSeparator sep(" :: "); - for (Nonnull frame : cast(*this).Stack()) { + for (Nonnull frame : *cast(*this).Stack()) { out << sep << *frame; } out << "}"; @@ -352,8 +352,8 @@ auto CopyVal(Nonnull arena, Nonnull val, case Value::Kind::PointerValue: return arena->New(cast(*val).Val()); case Value::Kind::ContinuationValue: - // Copying a continuation is "shallow". - return val; + return arena->New( + cast(*val).Stack()); case Value::Kind::FunctionType: { const auto& fn_type = cast(*val); return arena->New( diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index 7c28dfe8a9e7..be87d8aed1a1 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -493,19 +493,25 @@ class VariableType : public Value { }; // A first-class continuation representation of a fragment of the stack. +// A continuation value behaves like a pointer to the underlying stack +// fragment, which is exposed by `Stack()`. class ContinuationValue : public Value { public: - explicit ContinuationValue(std::vector> stack) - : Value(Kind::ContinuationValue), stack(std::move(stack)) {} + explicit ContinuationValue(Nonnull>*> stack) + : Value(Kind::ContinuationValue), stack(stack) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::ContinuationValue; } - auto Stack() const -> const std::vector>& { return stack; } + // The call stack of the suspended continuation, starting with the top + // frame (the reverse of the usual order). Note that this provides mutable + // access, even when *this is const, because of the reference-like semantics + // of ContinuationValue. + auto Stack() const -> Nonnull>*> { return stack; } private: - std::vector> stack; + Nonnull>*> stack; }; // The String type. diff --git a/executable_semantics/testdata/experimental_continuation/copy_in_continuation.carbon b/executable_semantics/testdata/experimental_continuation/copy_in_continuation.carbon deleted file mode 100644 index 2da75da184fc..000000000000 --- a/executable_semantics/testdata/experimental_continuation/copy_in_continuation.carbon +++ /dev/null @@ -1,32 +0,0 @@ -// Part of the Carbon Language project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// RUN: executable_semantics %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes=false %s -// RUN: executable_semantics --trace %s 2>&1 | \ -// RUN: FileCheck --match-full-lines --allow-unused-prefixes %s -// AUTOUPDATE: executable_semantics %s -// CHECK: result: 3 - -package ExecutableSemanticsTest api; - -// Test the way in which copying of continuations interacts with data -// on the stack such as the variable `x`. In this example the copy -// happens after the variable `x` is created. - -var y: i32 = 0; - -fn main() -> i32 { - __continuation k1 { - var x: i32 = 0; - x = x + 1; - __await; - x = x + 2; - y = x; - } - __run k1; - var k2: __Continuation = k1; - __run k2; - return y; -} diff --git a/executable_semantics/testdata/experimental_continuation/shallow_copy.carbon b/executable_semantics/testdata/experimental_continuation/shallow_copy.carbon index 5399cc8750e7..c244bfd00c87 100644 --- a/executable_semantics/testdata/experimental_continuation/shallow_copy.carbon +++ b/executable_semantics/testdata/experimental_continuation/shallow_copy.carbon @@ -14,12 +14,17 @@ package ExecutableSemanticsTest api; // Assignment for continuations is shallow, so `k2` refers to the same // continuation as `k1`. +var x: i32 = 0; + +fn Foo() { + x = x + 1; + __await; + x = x + 2; +} + fn main() -> i32 { - var x: i32 = 0; __continuation k1 { - x = x + 1; - __await; - x = x + 2; + Foo(); } var k2: __Continuation = k1; __run k1;