Skip to content

Commit

Permalink
OCaml 5.2 support (#7)
Browse files Browse the repository at this point in the history
* OCaml 5.2 support

This patch adds OCaml 5.2 support. The main change is to account for
the new continuation representation in OCaml 5.2, which represents a
continuation as a pair. Legacy support is preserved via the use of the
compile-time `MULTICONT52` variable. When toggled code for the new
continuation representation is included, otherwise this code is
excluded.

Resolves #6.

* Use ocaml-5.2.0+trunk in CI until the proper release is available.

* Follow the OCaml manual's FFI rules even if they may not be strictly required.
  • Loading branch information
dhil committed Mar 6, 2024
1 parent 43b1659 commit 94dee45
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
1 change: 1 addition & 0 deletions .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
- ubuntu-22.04
ocaml-compiler:
- 5.1.0
- ocaml-variants.5.2.0+trunk

runs-on: ${{ matrix.os }}

Expand Down
44 changes: 39 additions & 5 deletions lib/multicont_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,49 @@
#include "fiber_primitives.h" // provides [MULTICONT_NEXT_FIBER_ID]
// generator.

// NOTE(dhil): The representation of continuations was changed in
// OCaml 5.2. In OCaml 5.2+ a continuation is a pair of stack segments
// (first_segment, last_segment) which together forms the complete
// stack chain from effect invocation site to handle site. Here,
// first_segment is the segment where the effect was initially
// performed and last_segment is segment that had the appropriate
// handler installed.
//
// Prior to OCaml 5.2 the continuation was simply a pointer to
// previous stack segment that performed or reperformed the effect.
#if OCAML_VERSION_MAJOR >= 5 && OCAML_VERSION_MINOR > 1
#error "multicont is not yet supported on OCaml 5.2+"
#define MULTICONT52 1
#else
#define MULTICONT52 0
#endif

value multicont_promote(value k) {
CAMLprim value multicont_promote(value k) {
CAMLparam1(k);
CAMLlocal1(r);

value null_stk = Val_ptr(NULL);

#if MULTICONT52
r = caml_alloc_2(Cont_tag, null_stk, null_stk);
#else
r = caml_alloc_1(Cont_tag, null_stk);
#endif

// Move the stack from [k] to [r]
{
// Prevent the GC from running between [caml_continuation_use] and
// [caml_continuation_replace]
CAMLnoalloc;
caml_continuation_replace(r, Ptr_val(caml_continuation_use(k)));
#if MULTICONT52
caml_modify(&Field(r, 1), Field(k, 1));
#endif
}

CAMLreturn(r);
}

value multicont_clone_continuation(value k) {
CAMLprim value multicont_clone_continuation(value k) {
CAMLparam1(k); // input continuation object
CAMLlocal1(kclone); // resulting continuation object clone

Expand All @@ -51,9 +70,16 @@ value multicont_clone_continuation(value k) {
*clone, // clone of [current]
*result; // clone of [source]
struct stack_info **link = &result;
#if MULTICONT52
struct stack_info *last_segment; // the last segment of the stack chain
#endif

// Allocate an OCaml object with the continuation tag
#if MULTICONT52
kclone = caml_alloc_2(Cont_tag, null_stk, null_stk);
#else
kclone = caml_alloc_1(Cont_tag, null_stk);
#endif
{
// Prevent the GC from running between the use of
// [caml_continuation_use] and [caml_continuation_replace]
Expand Down Expand Up @@ -97,11 +123,18 @@ value multicont_clone_continuation(value k) {
clone->sp = Stack_high(clone) - space_used;

// Prepare to handle the next stack segment
#if MULTICONT52
last_segment = clone;
#endif
*link = clone;
link = &Stack_parent(clone);
current = Stack_parent(current);
}

#if MULTICONT52
caml_modify(&Field(kclone, 1), Val_ptr(last_segment));
#endif

// Reattach the [source] stack to [k] (necessary as
// [caml_continuation_use] deattaches it) and attach [result] to
// [kclone]
Expand All @@ -112,13 +145,14 @@ value multicont_clone_continuation(value k) {
CAMLreturn(kclone);
}

value multicont_drop_continuation(value k) {
CAMLprim value multicont_drop_continuation(value k) {
CAMLparam1(k);
struct stack_info *current,
*next = Ptr_val(caml_continuation_use(k));
while (next != NULL) {
current = next;
next = Stack_parent(current);
caml_free_stack(current);
}
return Val_unit;
CAMLreturn(Val_unit);
}

0 comments on commit 94dee45

Please sign in to comment.