update shape code to handle iface instances
This commit is contained in:
parent
0e334c6839
commit
441a42c5d2
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
45
src/test/run-pass/iface-cast.rs
Normal file
45
src/test/run-pass/iface-cast.rs
Normal 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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user