From 441a42c5d2707ae93a8be3c6be5c426e7416e50b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 10 Jan 2012 19:04:09 -0800 Subject: [PATCH] update shape code to handle iface instances --- src/rt/rust_cc.cpp | 9 +++++++ src/rt/rust_internal.h | 17 +++++++++++++ src/rt/rust_shape.h | 21 ++++++++------- src/test/run-pass/iface-cast.rs | 45 +++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 src/test/run-pass/iface-cast.rs diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp index bf872700f0ec..a96c3739ca3f 100644 --- a/src/rt/rust_cc.cpp +++ b/src/rt/rust_cc.cpp @@ -110,6 +110,11 @@ class irc : public shape::data { maybe_record_irc(ref_count_dp); } + void walk_iface() { + // an iface is always a ptr to a ref-counted obj. + shape::data::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 { return; } + void walk_iface() { + shape::data::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) { diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index b83d74f6bfe3..f9300cad443b 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -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; diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h index e3041f238544..ca8cd2c88a54 100644 --- a/src/rt/rust_shape.h +++ b/src/rt/rust_shape.h @@ -868,7 +868,12 @@ public: dp = next_dp; } - void walk_iface() { DATA_SIMPLE(void *, walk_iface()); } + void walk_iface() { + ALIGN_TO(alignof()); + U next_dp = dp + sizeof(void *) * 2; + static_cast(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::walk_obj_contents(ptr &dp) { template void data::walk_iface_value(ptr &dp) { - uint8_t *box_ptr = bump_dp(dp); + opaque_iface *box_ptr = bump_dp(dp); if (!box_ptr) return; - uint8_t *body_ptr = box_ptr + sizeof(void*); - type_desc *valtydesc = - *reinterpret_cast(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(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(this), contents_td->shape, NULL, NULL, contents_dp); sub.align = true; sub.walk(); } diff --git a/src/test/run-pass/iface-cast.rs b/src/test/run-pass/iface-cast.rs new file mode 100644 index 000000000000..05da479f8647 --- /dev/null +++ b/src/test/run-pass/iface-cast.rs @@ -0,0 +1,45 @@ +// Test cyclic detector when using iface instances. + +tag Tree = TreeR; +type TreeR = @{ + mutable left: option, + mutable right: option, + val: to_str +}; + +iface to_str { + fn to_str() -> str; +} + +impl of to_str for option { + 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 +}