ssm  0.0.2
Runtime Library for the Sparse Synchronous Model
Closures

Discussion

The SSM runtime supports closures, a runtime representation for functions. These encapsulate a function pointer (specifically, an enter function pointer) and a vector of partially-applied arguments (referred to as argv).

When closures are applied to arguments, they may or may not reduce. When a reduction takes place, a child process is created: the enter function pointer is applied to argv, and the resulting activation record is scheduled via ssm_activate(). If this happens, the caller must yield (i.e., set the program counter and return) so that the child process may run to completion before the caller resumes.

It might be possible to statically determine whether a caller needs to yield, so in the general case, the caller should yield conditionally, using ssm_has_children() to determine whether any reduction took place. Optimizations may eliminate this check.

Closures are allocated with enough space for all eventual arguments to be stored in argv, which is in turn passed to the callee. Though this wastes extra space, it vastly increases opportunities to reuse the same closure (if it is uniquely owned by the caller).

Closures' ssm_mm headers are vector-flavored; the cap field indicates how many arguments the closure is allocated with (i.e., how many can be applied to it), while the count field indicates how many arguments are currently applied. cap is used to determine the size, while count is used to determine how many valid values the garbage collector needs to scan when a closure is deallocated.

The "template" for each closure's memory layout is defined by ssm_closure1; closures with more argument capacity look like ssm_closure1 with a longer argv.

The function ssm_closure_apply() applies a closure to an argument, with or without reduction. The SSM runtime library defines many helper interfaces to allow compilers to generate optimized code for interacting with closures. For example, ssm_closure_push() and ssm_closure_pop() directly add and remove arguments to argv without any runtime checks or function call overhead. ssm_closure_apply() is implemented in terms of these helpers, and should be inlined by an optimizing code generator where appropriate.

Meanwhile, ssm_closure_apply_final() optimizes the last time a closure value is used. It assumes that the caller is releasing the last remaining reference to a closure, so that the closure may be safely modified in-place.

When process a applies function f to argument x, and saves the result to r, the most general case (omitting reference-counting) looks like:

ssm_closure_apply(f, x, a, a->priority, a->depth, &r);
a->pc = N;
return;
case N:;
}
#define ssm_has_children(act)
Whether an activation record has any children.
Definition: ssm.h:148
void ssm_closure_apply(ssm_value_t closure, ssm_value_t arg, ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *ret)
Apply an argument to a closure.
Definition: ssm-closure.c:25

where N is the running program counter.

For convenience, _auto variants of ssm_closure_apply() and ssm_closure_apply_final() call ssm_dup() on the argument.

Data Structures

struct  ssm_closure1
 The struct template of a heap-allocated closure object. More...
 

Macros

#define ssm_closure_arg_count(v)    (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.count)
 Obtain the number of argument values owned by a closure. More...
 
#define ssm_closure_arg_cap(v)    (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.cap)
 Obtain the number of argument values accommodated by a closure. More...
 
#define ssm_closure_func(v)    (container_of((v).heap_ptr, struct ssm_closure1, mm)->f)
 Obtain the enter function pointer of a closure. More...
 
#define ssm_closure_argv(v)    (&*container_of((v).heap_ptr, struct ssm_closure1, mm)->argv)
 Retrieve the argument array of a closure. More...
 
#define ssm_closure_arg(v, i)   ssm_closure_argv(v)[i]
 Obtain the ith argument of a closure. More...
 
#define ssm_closure_size(val_count)    (sizeof(struct ssm_closure1) + (sizeof(ssm_value_t) * ((val_count)-1)))
 Compute the size of a closure object. More...
 
#define ssm_closure_heap_size(v)   ssm_closure_size(ssm_closure_arg_cap(v))
 Compute the size of a closure already allocated on the heap. More...
 
#define ssm_closure_push(closure, arg)
 Add an argument to a closure. More...
 
#define ssm_closure_pop(closure)
 Remove an argument from a closure. More...
 
#define ssm_closure_activate(closure, parent, prio, depth, ret)
 Spawn and schedule a new child process from a fully-applied closure. More...
 
#define ssm_new_closure(f, args)
 
#define ssm_closure_apply_auto(closure, arg, parent, prio, depth, ret)
 Closure application with automatic memory management. More...
 
#define ssm_closure_apply_final_auto(closure, arg, parent, prio, depth, ret)
 In-place closure application with automatic memory management. More...
 
#define ssm_closure_free(closure)
 Helper to free a closure (without reference counting). More...
 

Typedefs

typedef ssm_act_t *(* ssm_func_t) (ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *argv, ssm_value_t *ret)
 The type signature for all SSM enter functions. More...
 

Functions

ssm_value_t ssm_new_closure_int (ssm_func_t f, uint8_t arg_cap)
 Allocate a closure on the heap. More...
 
ssm_value_t ssm_closure_clone (ssm_value_t closure)
 Create a copy of a closure. More...
 
void ssm_closure_apply (ssm_value_t closure, ssm_value_t arg, ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *ret)
 Apply an argument to a closure. More...
 
void ssm_closure_apply_final (ssm_value_t closure, ssm_value_t arg, ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *ret)
 Apply an argument to a closure that is used for the last time. More...
 

Macro Definition Documentation

◆ ssm_closure_arg_count

#define ssm_closure_arg_count (   v)     (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.count)

Obtain the number of argument values owned by a closure.

Definition at line 811 of file ssm.h.

◆ ssm_closure_arg_cap

#define ssm_closure_arg_cap (   v)     (container_of((v).heap_ptr, struct ssm_closure1, mm)->mm.info.vector.cap)

Obtain the number of argument values accommodated by a closure.

Definition at line 815 of file ssm.h.

◆ ssm_closure_func

#define ssm_closure_func (   v)     (container_of((v).heap_ptr, struct ssm_closure1, mm)->f)

Obtain the enter function pointer of a closure.

Definition at line 819 of file ssm.h.

◆ ssm_closure_argv

#define ssm_closure_argv (   v)     (&*container_of((v).heap_ptr, struct ssm_closure1, mm)->argv)

Retrieve the argument array of a closure.

Definition at line 823 of file ssm.h.

◆ ssm_closure_arg

#define ssm_closure_arg (   v,
 
)    ssm_closure_argv(v)[i]

Obtain the ith argument of a closure.

Definition at line 827 of file ssm.h.

◆ ssm_closure_size

#define ssm_closure_size (   val_count)     (sizeof(struct ssm_closure1) + (sizeof(ssm_value_t) * ((val_count)-1)))

Compute the size of a closure object.

Parameters
val_countthe val_count field of the closure's ssm_mm header.
Returns
the size of the closure object.

Definition at line 834 of file ssm.h.

◆ ssm_closure_heap_size

#define ssm_closure_heap_size (   v)    ssm_closure_size(ssm_closure_arg_cap(v))

Compute the size of a closure already allocated on the heap.

Definition at line 838 of file ssm.h.

◆ ssm_closure_push

#define ssm_closure_push (   closure,
  arg 
)
Value:
ssm_closure_arg(closure, ssm_closure_arg_count(closure)++) = (arg); \
while (0)
#define ssm_closure_arg_count(v)
Obtain the number of argument values owned by a closure.
Definition: ssm.h:811
#define ssm_closure_arg(v, i)
Obtain the ith argument of a closure.
Definition: ssm.h:827

Add an argument to a closure.

Note that this helper increments the arg_count of closure but does not perform memory management, i.e., does not ssm_dup() arg. It also does not check whether closure has capacity for arg.

Definition at line 846 of file ssm.h.

◆ ssm_closure_pop

#define ssm_closure_pop (   closure)
Value:
while (0)

Remove an argument from a closure.

Note that this helper decrements the arg_count of closure but does not perform memory management, i.e., does not ssm_drop() arg. It also does not check whether closure has a non-zero number of arguments already applied.

Definition at line 858 of file ssm.h.

◆ ssm_closure_activate

#define ssm_closure_activate (   closure,
  parent,
  prio,
  depth,
  ret 
)
Value:
ssm_activate(ssm_closure_func(closure)(parent, prio, depth, \
ssm_closure_argv(closure), ret))
void ssm_activate(ssm_act_t *act)
Schedule a routine to run in the current instant.
#define ssm_closure_argv(v)
Retrieve the argument array of a closure.
Definition: ssm.h:823
#define ssm_closure_func(v)
Obtain the enter function pointer of a closure.
Definition: ssm.h:819

Spawn and schedule a new child process from a fully-applied closure.

Note that this helper does not perform any memory management, nor does it ensure that closure has all arguments applied.

Definition at line 868 of file ssm.h.

◆ ssm_new_closure

#define ssm_new_closure (   f,
  args 
)
Value:
(fprintf(stderr, "%s:%d:ssm_new_closure(_, %d)\n", __FILE__, __LINE__, \
(args)), \
ssm_new_closure_int((f), (args)))

Definition at line 880 of file ssm.h.

◆ ssm_closure_apply_auto

#define ssm_closure_apply_auto (   closure,
  arg,
  parent,
  prio,
  depth,
  ret 
)
Value:
do { \
ssm_dup(arg); \
ssm_closure_apply(closure, arg, parent, prio, depth, ret); \
} while (0)

Closure application with automatic memory management.

ssm_dup() is called on a before f is applied to it; see ssm_closure_apply().

Parameters
closurethe closure to be applied.
argthe argument closure is applied to.
parentthe current process performing the application.
priopriority of the current process.
depthdepth of the current process.
retpointer to the return value.

Definition at line 971 of file ssm.h.

◆ ssm_closure_apply_final_auto

#define ssm_closure_apply_final_auto (   closure,
  arg,
  parent,
  prio,
  depth,
  ret 
)
Value:
do { \
ssm_dup(arg); \
ssm_closure_apply_final(closure, arg, parent, prio, depth, ret); \
} while (0)

In-place closure application with automatic memory management.

ssm_dup() is called on a before f is applied to it; see ssm_closure_apply_final().

Parameters
closurethe closure to be applied.
argthe argument closure is applied to.
parentthe current process performing the application.
priopriority of the current process.
depthdepth of the current process.
retpointer to the return value.

Definition at line 989 of file ssm.h.

◆ ssm_closure_free

#define ssm_closure_free (   closure)
Value:
ssm_mem_free((closure).heap_ptr, \
#define ssm_closure_size(val_count)
Compute the size of a closure object.
Definition: ssm.h:834
#define ssm_closure_arg_cap(v)
Obtain the number of argument values accommodated by a closure.
Definition: ssm.h:815
void ssm_mem_free(void *m, size_t size)
Deallocate memory allocated by ssm_mem_alloc().
Definition: ssm-mem.c:233

Helper to free a closure (without reference counting).

Definition at line 996 of file ssm.h.

Typedef Documentation

◆ ssm_func_t

typedef ssm_act_t*(* ssm_func_t) (ssm_act_t *parent, ssm_priority_t prio, ssm_depth_t depth, ssm_value_t *argv, ssm_value_t *ret)

The type signature for all SSM enter functions.

This type standardizes the "calling convention" of SSM functions, so that they can be stored in generic closures and treated uniformly.

Parameters
parentthe activation record of the caller.
priothe priority of the callee.
depththe depth of the callee.
argvan array of ssm_value_t arguments given to the callee.
retthe return value address that the callee should write to.
Returns
an allocated activation record for the callee.

Definition at line 783 of file ssm.h.

Function Documentation

◆ ssm_new_closure_int()

ssm_value_t ssm_new_closure_int ( ssm_func_t  f,
uint8_t  arg_cap 
)

Allocate a closure on the heap.

Parameters
fthe enter function pointer of the closure.
arg_capthe number of arguments the closure should accommodate.
Returns
a value pointing to the heap-allocated closure.

Definition at line 294 of file ssm-mem.c.

◆ ssm_closure_clone()

ssm_value_t ssm_closure_clone ( ssm_value_t  closure)

Create a copy of a closure.

Note
Calls ssm_dup() on all previously applied arguments.
Parameters
closurethe closure to be copied.
Returns
a value pointing to the heap-allocated closure.

Definition at line 12 of file ssm-closure.c.

◆ ssm_closure_apply()

void ssm_closure_apply ( ssm_value_t  closure,
ssm_value_t  arg,
ssm_act_t parent,
ssm_priority_t  prio,
ssm_depth_t  depth,
ssm_value_t ret 
)

Apply an argument to a closure.

The behavior depends on whether closure needs to be activated after being applied to arg, i.e., whether all of its arguments have arrived.

If closure is activated, a child process will be scheduled, so the caller must yield to the scheduler to allow the child process to run. The child process will write its return value to ret.

If closure is not activated, a copy of it (via ssm_closure_clone()) with arg pushed to its argv will be written to ret.

In both cases, all values in closure's argv will have ssm_dup() called on them, since application will result in those values being shared in a new context, either from a child process or from the cloned closure. Note that ssm_dup() is not called on arg; to do so automatically, use ssm_closure_apply_auto().

Parameters
closurethe closure to be applied.
argthe argument closure is applied to.
parentthe current process performing the application.
priopriority of the current process.
depthdepth of the current process.
retpointer to the return value.

Definition at line 25 of file ssm-closure.c.

◆ ssm_closure_apply_final()

void ssm_closure_apply_final ( ssm_value_t  closure,
ssm_value_t  arg,
ssm_act_t parent,
ssm_priority_t  prio,
ssm_depth_t  depth,
ssm_value_t ret 
)

Apply an argument to a closure that is used for the last time.

An optimized version of ssm_closure_apply(), to be used only provided:

  1. this is the last time closure is used by the caller.
  2. no other processes share closure.

This implementation should be used as the fast path when those conditions hold; it improves upon the more general ssm_closure_apply() by using closure in-place, and avoiding unnecessary ssm_dup() and ssm_drop() called. After this is called, closure will not need to be dropped.

The behavior of this function is equivalent to:

ssm_closure_apply(f, a, p, prio, depth, ret);
#define ssm_drop(v)
Drop a reference to a possible heap item, and free it if necessary.
Definition: ssm.h:338

Like ssm_closure_apply(), this function does not ssm_drop() arg; to do so automatically, use ssm_closure_apply_final_auto().

Parameters
closurethe closure to be applied.
argthe argument closure is applied to.
parentthe current process performing the application.
priopriority of the current process.
depthdepth of the current process.
retpointer to the return value.

Definition at line 43 of file ssm-closure.c.