update shape code to handle iface instances

This commit is contained in:
Niko Matsakis 2012-01-10 19:04:09 -08:00
parent 0e334c6839
commit 441a42c5d2
4 changed files with 81 additions and 11 deletions

View File

@ -110,6 +110,11 @@ class irc : public shape::data<irc,shape::ptr> {
maybe_record_irc(ref_count_dp);
}
void walk_iface() {
// an iface is always a ptr to a ref-counted obj.
shape::data<irc,shape::ptr>::walk_box_contents();
}
void walk_res(const shape::rust_fn *dtor, unsigned n_params,
const shape::type_param *params, const uint8_t *end_sp,
bool live) {
@ -497,6 +502,10 @@ class sweep : public shape::data<sweep,shape::ptr> {
return;
}
void walk_iface() {
shape::data<sweep,shape::ptr>::walk_box_contents();
}
void walk_res(const shape::rust_fn *dtor, unsigned n_params,
const shape::type_param *params, const uint8_t *end_sp,
bool live) {

View File

@ -260,6 +260,23 @@ struct rust_opaque_closure;
// no arguments (and hence the final void*) is harmless
typedef void (*CDECL spawn_fn)(void*, rust_opaque_closure*, void *);
// corresponds to the layout of an iface value
//
// Note: eventually, we should inline the contents of opaque_iface_contents
// into opaque_iface in the LLVM code. Otherwise, the alignment of
// opaque_iface_contents depends on the opaque data!
struct opaque_iface_contents {
const type_desc *td; // describes opaque_iface_contents
const void *vtable;
// (opaque data goes here)
};
struct opaque_iface {
intptr_t ref_count;
opaque_iface_contents contents;
};
// corresponds to the layout of a fn(), fn@(), fn~() etc
struct fn_env_pair {
spawn_fn f;

View File

@ -868,7 +868,12 @@ public:
dp = next_dp;
}
void walk_iface() { DATA_SIMPLE(void *, walk_iface()); }
void walk_iface() {
ALIGN_TO(alignof<void *>());
U next_dp = dp + sizeof(void *) * 2;
static_cast<T *>(this)->walk_iface();
dp = next_dp;
}
void walk_res(const rust_fn *dtor, unsigned n_params,
const type_param *params, const uint8_t *end_sp) {
@ -999,17 +1004,11 @@ data<T,U>::walk_obj_contents(ptr &dp) {
template<typename T,typename U>
void
data<T,U>::walk_iface_value(ptr &dp) {
uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
opaque_iface *box_ptr = bump_dp<opaque_iface *>(dp);
if (!box_ptr) return;
uint8_t *body_ptr = box_ptr + sizeof(void*);
type_desc *valtydesc =
*reinterpret_cast<type_desc **>(body_ptr);
ptr value_dp(body_ptr + sizeof(void*) * 2);
// FIXME The 5 is a hard-coded way to skip over a struct shape
// header and the first two (number-typed) fields. This is too
// fragile, but I didn't see a good way to properly encode it.
T sub(*static_cast<T *>(this), valtydesc->shape + 5, NULL, NULL,
value_dp);
const type_desc *contents_td = box_ptr->contents.td;
ptr contents_dp((uintptr_t)&box_ptr->contents);
T sub(*static_cast<T *>(this), contents_td->shape, NULL, NULL, contents_dp);
sub.align = true;
sub.walk();
}

View File

@ -0,0 +1,45 @@
// Test cyclic detector when using iface instances.
tag Tree = TreeR;
type TreeR = @{
mutable left: option<Tree>,
mutable right: option<Tree>,
val: to_str
};
iface to_str {
fn to_str() -> str;
}
impl <T: to_str> of to_str for option<T> {
fn to_str() -> str {
alt self {
none. { "none" }
some(t) { "some(" + t.to_str() + ")" }
}
}
}
impl of to_str for int {
fn to_str() -> str { int::str(self) }
}
impl of to_str for Tree {
fn to_str() -> str {
#fmt["[%s, %s, %s]",
self.val.to_str(),
self.left.to_str(),
self.right.to_str()]
}
}
fn main() {
let t1 = Tree(@{mutable left: none,
mutable right: none,
val: 1 as to_str });
let t2 = Tree(@{mutable left: some(t1),
mutable right: some(t1),
val: 2 as to_str });
assert t2.to_str() == "[2, some([1, none, none]), some([1, none, none])]";
t1.left = some(t2); // create cycle
}