Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
Implement cont.bind (#41)
Browse files Browse the repository at this point in the history
This patch implements the `cont.bind` operator.
  • Loading branch information
frank-emrich authored Jul 11, 2023
1 parent a4ede0e commit 5ec1917
Show file tree
Hide file tree
Showing 12 changed files with 453 additions and 41 deletions.
24 changes: 20 additions & 4 deletions cranelift/filetests/src/test_wasm/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@ impl<'a> FuncEnvironment for FuncEnv<'a> {
builder: &mut cranelift_frontend::FunctionBuilder,
state: &cranelift_wasm::FuncTranslationState,
tag_index: u32,
) {
self.inner.translate_suspend(builder, state, tag_index)
) -> ir::Value {
return self.inner.translate_suspend(builder, state, tag_index);
}

/// TODO
Expand Down Expand Up @@ -767,10 +767,15 @@ impl<'a> FuncEnvironment for FuncEnv<'a> {
&mut self,
builder: &mut cranelift_frontend::FunctionBuilder,
values: &[ir::Value],
remaining_arg_count: ir::Value,
contobj: ir::Value,
) {
self.inner
.typed_continuations_store_resume_args(builder, values, contobj)
self.inner.typed_continuations_store_resume_args(
builder,
values,
remaining_arg_count,
contobj,
)
}

/// TODO
Expand All @@ -792,4 +797,15 @@ impl<'a> FuncEnvironment for FuncEnv<'a> {
self.inner
.typed_continuations_cont_ref_get_cont_obj(builder, contref)
}

fn typed_continuations_load_tag_return_values(
&mut self,
builder: &mut cranelift_frontend::FunctionBuilder,
contobj: ir::Value,
valtypes: &[wasmtime_types::WasmType],
) -> Vec<ir::Value> {
return self
.inner
.typed_continuations_load_tag_return_values(builder, contobj, valtypes);
}
}
29 changes: 24 additions & 5 deletions cranelift/wasm/src/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2589,18 +2589,37 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
environ.typed_continuations_store_payloads(builder, &param_types, params);
state.popn(param_count);

environ.translate_suspend(builder, state, *tag_index);
let vmctx = environ.translate_suspend(builder, state, *tag_index);

let contobj = environ.typed_continuations_load_continuation_object(builder, vmctx);

let return_types = environ.tag_returns(*tag_index).to_vec();
let return_values = environ.typed_continuations_load_payloads(builder, &return_types);
let return_values =
environ.typed_continuations_load_tag_return_values(builder, contobj, &return_types);

state.pushn(&return_values);
}
Operator::ContBind {
src_index: _,
dst_index: _,
src_index,
dst_index,
} => {
let src_arity = environ.continuation_arguments(*src_index).len();
let dst_arity = environ.continuation_arguments(*dst_index).len();
let arg_count = src_arity - dst_arity;

let (original_contref, args) = state.peekn(arg_count + 1).split_last().unwrap();
let contobj =
environ.typed_continuations_cont_ref_get_cont_obj(builder, *original_contref);

let src_arity_value = builder.ins().iconst(I32, src_arity as i64);
environ.typed_continuations_store_resume_args(builder, args, src_arity_value, contobj);

let new_contref = environ.typed_continuations_new_cont_ref(builder, contobj);

state.popn(arg_count + 1);
state.push1(new_contref);
}
| Operator::ResumeThrow {
Operator::ResumeThrow {
type_index: _,
tag_index: _,
resumetable: _,
Expand Down
12 changes: 11 additions & 1 deletion cranelift/wasm/src/environ/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
_builder: &mut FunctionBuilder,
_state: &FuncTranslationState,
_tag_index: u32,
) {
) -> ir::Value {
todo!()
}

Expand Down Expand Up @@ -738,10 +738,20 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
todo!()
}

fn typed_continuations_load_tag_return_values(
&mut self,
_builder: &mut FunctionBuilder,
_contobj: ir::Value,
_valtypes: &[WasmType],
) -> Vec<ir::Value> {
todo!()
}

fn typed_continuations_store_resume_args(
&mut self,
_builder: &mut FunctionBuilder,
_values: &[ir::Value],
_remaining_arg_count: ir::Value,
_contref: ir::Value,
) {
todo!()
Expand Down
11 changes: 10 additions & 1 deletion cranelift/wasm/src/environ/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ pub trait FuncEnvironment: TargetEnvironment {
builder: &mut FunctionBuilder,
state: &FuncTranslationState,
tag_index: u32,
);
) -> ir::Value;

/// TODO
fn continuation_arguments(&self, type_index: u32) -> &[wasmtime_types::WasmType];
Expand All @@ -625,6 +625,14 @@ pub trait FuncEnvironment: TargetEnvironment {
valtypes: &[wasmtime_types::WasmType],
) -> std::vec::Vec<ir::Value>;

/// TODO
fn typed_continuations_load_tag_return_values(
&mut self,
builder: &mut FunctionBuilder,
contobj: ir::Value,
valtypes: &[wasmtime_types::WasmType],
) -> std::vec::Vec<ir::Value>;

/// TODO
fn typed_continuations_store_payloads(
&mut self,
Expand All @@ -638,6 +646,7 @@ pub trait FuncEnvironment: TargetEnvironment {
&mut self,
builder: &mut FunctionBuilder,
values: &[ir::Value],
remaining_arg_count: ir::Value,
contobj: ir::Value,
);

Expand Down
58 changes: 53 additions & 5 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2292,7 +2292,8 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
// Second: Call the `resume` builtin

if call_args.len() > 0 {
self.typed_continuations_store_resume_args(builder, call_args, contobj);
let count = builder.ins().iconst(I32, call_args.len() as i64);
self.typed_continuations_store_resume_args(builder, call_args, count, contobj);
}

let (vmctx, result) = generate_builtin_call!(self, builder, resume, [contobj]);
Expand Down Expand Up @@ -2328,10 +2329,11 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
builder: &mut FunctionBuilder,
_state: &FuncTranslationState,
tag_index: u32,
) {
) -> ir::Value {
let tag_index = builder.ins().iconst(I32, tag_index as i64);

generate_builtin_call_no_return_val!(self, builder, suspend, [tag_index]);
// Returns the vmctx
return generate_builtin_call_no_return_val!(self, builder, suspend, [tag_index]);
}

fn continuation_arguments(&self, index: u32) -> &[WasmType] {
Expand Down Expand Up @@ -2390,6 +2392,47 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
values
}

fn typed_continuations_load_tag_return_values(
&mut self,
builder: &mut FunctionBuilder,
contobj: ir::Value,
valtypes: &[WasmType],
) -> Vec<ir::Value> {
let memflags = ir::MemFlags::trusted();
let mut values = vec![];

if valtypes.len() > 0 {
let nargs = builder.ins().iconst(I32, valtypes.len() as i64);

let (_vmctx, payload_ptr) = generate_builtin_call!(
self,
builder,
cont_obj_get_tag_return_values_buffer,
[contobj, nargs]
);

let mut offset = 0;
for valtype in valtypes {
let val = builder.ins().load(
super::value_type(self.isa, *valtype),
memflags,
payload_ptr,
offset,
);
values.push(val);
offset += self.offsets.ptr.maximum_value_size() as i32;
}

generate_builtin_call_no_return_val!(
self,
builder,
cont_obj_deallocate_tag_return_values_buffer,
[contobj]
);
}
values
}

/// TODO
fn typed_continuations_cont_ref_get_cont_obj(
&mut self,
Expand All @@ -2406,6 +2449,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
&mut self,
builder: &mut FunctionBuilder,
values: &[ir::Value],
remaining_arg_count: ir::Value,
contobj: ir::Value,
) {
let nargs = builder.ins().iconst(I32, values.len() as i64);
Expand Down Expand Up @@ -2438,8 +2482,12 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
{
builder.switch_to_block(use_payloads_block);
builder.seal_block(use_payloads_block);
let (_vmctx, ptr) =
generate_builtin_call!(self, builder, alllocate_payload_buffer, [nargs]);
let (_vmctx, ptr) = generate_builtin_call!(
self,
builder,
cont_obj_occupy_next_tag_returns_slots,
[contobj, nargs, remaining_arg_count]
);
builder.ins().jump(store_data_block, &[ptr]);
}

Expand Down
20 changes: 19 additions & 1 deletion crates/environ/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ macro_rules! foreach_builtin_function {
/// Invoked when we reach a new epoch.
new_epoch(vmctx: vmctx) -> i64;
/// Creates a new continuation from a funcref.

cont_new(vmctx: vmctx, r: pointer, param_count: i64, result_count: i64) -> pointer;
/// Resumes a continuation.
resume(vmctx: vmctx, contobj: pointer) -> i32;
Expand All @@ -74,20 +75,37 @@ macro_rules! foreach_builtin_function {
//cont_obj_drop(vmctx: vmctx, contobj: pointer);
/// Crates a new continuation reference.
new_cont_ref(vmctx: vmctx, contobj: pointer) -> pointer;


/// Allocates a buffer large enough for storing `element_count` tag
/// payloads and stores it in the `VMContext` in such a way that
/// subsequent calls to `get_payload_buffer` will return the same
/// buffer.
/// Returns a pointer to that buffer.
/// Such a payload buffer is only used to store payloads provided
/// at a suspend site and read in a corresponding handler.
alllocate_payload_buffer(vmctx: vmctx, element_count: i32) -> pointer;
/// Counterpart to `alllocate_payload_buffer`, deallocating the
/// buffer. For debugging purposes, `expected_element_capacity`
/// should be the same value passed when allocating.
dealllocate_payload_buffer(vmctx: vmctx, expected_element_capacity: i32);
/// Returns pointer to the payload buffer. For debugging purposes,
/// Returns pointer to the payload buffer, whose function was described earlier.
/// `expected_element_capacity` should be the same value passed when
/// allocating.
get_payload_buffer(vmctx: vmctx, expected_element_capacity: i32) -> pointer;


/// Returns a pointer to the next empty slot within the tag return value buffer
/// of the given continuation object.
/// Such a buffer is used to store payloads provided by cont.bind and resume
/// and received at a suspend site.
/// The next `arg_count` slots within the buffer are marked as used.
/// If no such buffer currently exists, a new one is allocated.
cont_obj_occupy_next_tag_returns_slots(vmctx: vmctx, contobj: pointer, arg_count : i32, remaining_arg_count : i32) -> pointer;
/// Returns a pointer to the beginning of the tag return value buffer
cont_obj_get_tag_return_values_buffer(vmctx: vmctx, contobj: pointer, expected_count : i32) -> pointer;
/// Deallocated the tag return value buffer within the continuation object.
cont_obj_deallocate_tag_return_values_buffer(vmctx: vmctx, contobj: pointer);
}
};
}
Expand Down
Loading

0 comments on commit 5ec1917

Please sign in to comment.