Last active
January 2, 2016 16:09
-
-
Save kvanbere/8328504 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef void* function_t; | |
typedef void* prev_closure_t; | |
union arg_t { | |
void* box; // Pointer to a boxed thing (or closure) | |
int val; // Byval if it fits in 8 bytes | |
}; | |
// foo a b c d e = ... | |
struct closure_fn_foo { | |
arg_t a; // all these are zero from the block alloc | |
arg_t b; | |
arg_t c; | |
arg_t d; | |
arg_t e; | |
function_t fn; // initialized to a function pointer | |
prev_closure_t prev; // + sizeof(function_t) | |
int stack1; | |
int stack2; | |
double stack3; | |
}; | |
// bar x y = ... | |
struct closure_fn_bar { | |
arg_t x; | |
arg_t y; | |
function_t fn; | |
prev_closure_t prev; // + sizeof(function_t) | |
}; | |
// when the compiler can split apply/execute, this fast version can be used | |
// INLINE this. | |
void apply_fast(arg_t** closure, arg_t a) { | |
**closure = a; | |
*closure++; | |
} | |
// INLINE this. | |
void* execute(arg_t** closure /*, cont_t cont*/ ) { | |
return **closure(*closure /*, cont*/ ); | |
} | |
// For polymorphic types or (a -> b)s that can't be resolved at compile time | |
// INLINE this. | |
void apply_generic(arg_t** closure, arg_t a) { | |
**closure = a; | |
*closure++; | |
// if not zero by block alloc, we hit a function_t! cheats! | |
if (*closure) { | |
execute(closure); | |
// continuation blah | |
} | |
// continuation blah | |
} | |
// This is how you would make a PAP and use it | |
void test() { | |
void* something; | |
// The pointer starts at the top of the struct, and we erase the structs original type | |
// each application move it downwards (simple pointer arith) until we hit the function_t part | |
// then, the function called with the closure as the argument can access its stack in the positive members | |
// of the struct use sizeof()s. | |
void* p = gcalloc(sizeof(closure_fn_foo)); | |
p->fn = some_fn; // set the fn | |
// in some cases the closure might be linked to a previous lambda environment | |
// in that case, use linked closures. | |
p->prev = last_closure; | |
apply(&p, 1); | |
apply(&p, something); | |
// continuation blah | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment