Export adt::trans_get_discr abstractly to the type visitor.

This commit is contained in:
Jed Davis 2013-04-06 16:47:01 -07:00
parent 0ca1885da1
commit 640e8ae4e5
5 changed files with 150 additions and 22 deletions

View file

@ -15,6 +15,7 @@ Runtime type reflection
*/
use intrinsic::{TyDesc, TyVisitor};
#[cfg(not(stage0))] use intrinsic::Opaque;
use libc::c_void;
use sys;
use vec;
@ -393,6 +394,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}
#[cfg(stage0)]
fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint)
-> bool {
self.align(align);
@ -402,6 +404,18 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}
#[cfg(not(stage0))]
fn visit_enter_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
self.align(align);
if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
return false;
}
true
}
fn visit_enter_enum_variant(&self, variant: uint,
disr_val: int,
n_fields: uint,
@ -443,6 +457,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}
#[cfg(stage0)]
fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint)
-> bool {
if ! self.inner.visit_leave_enum(n_variants, sz, align) {
@ -452,6 +467,17 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}
#[cfg(not(stage0))]
fn visit_leave_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint) -> bool {
if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
return false;
}
self.bump(sz);
true
}
fn visit_trait(&self) -> bool {
self.align_to::<@TyVisitor>();
if ! self.inner.visit_trait() { return false; }

View file

@ -18,6 +18,7 @@ use cast::transmute;
use char;
use intrinsic;
use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
#[cfg(not(stage0))] use intrinsic::Opaque;
use io::{Writer, WriterUtil};
use libc::c_void;
use managed;
@ -137,12 +138,20 @@ impl Repr for char {
// New implementation using reflect::MovePtr
#[cfg(stage0)]
enum VariantState {
Degenerate,
TagMatch,
TagMismatch,
}
#[cfg(not(stage0))]
enum VariantState {
SearchingFor(int),
Matched,
AlreadyFound
}
pub struct ReprVisitor {
mut ptr: *c_void,
mut ptr_stk: ~[*c_void],
@ -181,26 +190,18 @@ pub impl ReprVisitor {
true
}
#[inline(always)]
#[cfg(stage0)] #[inline(always)]
fn bump(&self, sz: uint) {
do self.move_ptr() |p| {
((p as uint) + sz) as *c_void
};
}
#[inline(always)]
#[cfg(stage0)] #[inline(always)]
fn bump_past<T>(&self) {
self.bump(sys::size_of::<T>());
}
#[cfg(stage0)] #[inline(always)]
fn stage0_bump_past<T>(&self) {
self.bump_past::<T>();
}
#[cfg(not(stage0))] #[inline(always)]
fn stage0_bump_past<T>(&self) {
}
#[inline(always)]
fn visit_inner(&self, inner: *TyDesc) -> bool {
self.visit_ptr_inner(self.ptr, inner)
@ -466,6 +467,7 @@ impl TyVisitor for ReprVisitor {
true
}
#[cfg(stage0)]
fn visit_enter_enum(&self, n_variants: uint,
_sz: uint, _align: uint) -> bool {
if n_variants == 1 {
@ -476,6 +478,16 @@ impl TyVisitor for ReprVisitor {
true
}
#[cfg(not(stage0))]
fn visit_enter_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool {
let disr = unsafe { get_disr(transmute(self.ptr)) };
self.var_stk.push(SearchingFor(disr));
true
}
#[cfg(stage0)]
fn visit_enter_enum_variant(&self, _variant: uint,
disr_val: int,
n_fields: uint,
@ -495,7 +507,36 @@ impl TyVisitor for ReprVisitor {
self.var_stk.push(TagMismatch);
}
};
self.stage0_bump_past::<int>();
self.bump_past::<int>();
}
}
if write {
self.writer.write_str(name);
if n_fields > 0 {
self.writer.write_char('(');
}
}
true
}
#[cfg(not(stage0))]
fn visit_enter_enum_variant(&self, _variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
let mut write = false;
match self.var_stk.pop() {
SearchingFor(sought) => {
if disr_val == sought {
self.var_stk.push(Matched);
write = true;
} else {
self.var_stk.push(SearchingFor(sought));
}
}
Matched | AlreadyFound => {
self.var_stk.push(AlreadyFound);
}
}
@ -527,7 +568,7 @@ impl TyVisitor for ReprVisitor {
#[cfg(not(stage0))]
fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool {
match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
Degenerate | TagMatch => {
Matched => {
if i != 0 {
self.writer.write_str(", ");
}
@ -535,11 +576,12 @@ impl TyVisitor for ReprVisitor {
return false;
}
}
TagMismatch => ()
_ => ()
}
true
}
#[cfg(stage0)]
fn visit_leave_enum_variant(&self, _variant: uint,
_disr_val: int,
n_fields: uint,
@ -555,12 +597,38 @@ impl TyVisitor for ReprVisitor {
true
}
#[cfg(not(stage0))]
fn visit_leave_enum_variant(&self, _variant: uint,
_disr_val: int,
n_fields: uint,
_name: &str) -> bool {
match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
Matched => {
if n_fields > 0 {
self.writer.write_char(')');
}
}
_ => ()
}
true
}
#[cfg(stage0)]
fn visit_leave_enum(&self, _n_variants: uint,
_sz: uint, _align: uint) -> bool {
self.var_stk.pop();
true
}
#[cfg(not(stage0))]
fn visit_leave_enum(&self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool {
// NOTE should this assert that it's not still SearchingFor the right variant?
self.var_stk.pop();
true
}
fn visit_enter_fn(&self, _purity: uint, _proto: uint,
_n_inputs: uint, _retstyle: uint) -> bool { true }
fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {

View file

@ -28,6 +28,9 @@ pub mod intrinsic {
// Remaining fields not listed
}
// FIXME: make this a 0-variant enum; trans/reflect.rs has to match it.
pub type Opaque = ();
pub trait TyVisitor {
fn visit_bot(&self) -> bool;
fn visit_nil(&self) -> bool;
@ -91,6 +94,7 @@ pub mod intrinsic {
sz: uint, align: uint) -> bool;
fn visit_enter_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint) -> bool;
fn visit_enter_enum_variant(&self, variant: uint,
disr_val: int,
@ -102,6 +106,7 @@ pub mod intrinsic {
n_fields: uint,
name: &str) -> bool;
fn visit_leave_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint) -> bool;
fn visit_enter_fn(&self, purity: uint, proto: uint,

View file

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::llvm::{TypeRef, ValueRef};
use back::link::mangle_internal_name_by_path_and_seq;
use lib::llvm::{TypeRef, ValueRef, llvm};
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
@ -25,10 +25,13 @@ use middle::trans::type_of::*;
use middle::ty;
use util::ppaux::ty_to_str;
use core::libc::c_uint;
use core::option::None;
use core::vec;
use syntax::ast::def_id;
use syntax::ast;
use syntax::ast_map::path_name;
use syntax::parse::token::special_idents;
pub struct Reflector {
visitor_val: ValueRef,
@ -270,8 +273,28 @@ pub impl Reflector {
let ccx = bcx.ccx();
let repr = adt::represent_type(bcx.ccx(), t);
let variants = ty::substd_enum_variants(ccx.tcx, did, substs);
let llptrty = T_ptr(type_of(ccx, t));
let enum_args = ~[self.c_uint(vec::len(variants))]
// Build the get_disr function. (XXX: break this out into a function)
let sub_path = bcx.fcx.path + ~[path_name(special_idents::anon)];
let get_disr_sym = mangle_internal_name_by_path_and_seq(ccx, sub_path, ~"get_disr");
let get_disr_args = [ty::arg { mode: ast::expl(ast::by_copy),
ty: ty::mk_nil_ptr(ccx.tcx) }];
let get_disr_llfty = type_of_fn(ccx, get_disr_args, ty::mk_int(ccx.tcx));
let get_disr_llfdecl = decl_internal_cdecl_fn(ccx.llmod, get_disr_sym, get_disr_llfty);
let get_disr_arg = unsafe {
llvm::LLVMGetParam(get_disr_llfdecl, first_real_arg as c_uint)
};
let get_disr_fcx = new_fn_ctxt(ccx, ~[], get_disr_llfdecl, None);
let get_disr_bcx = top_scope_block(get_disr_fcx, None);
let get_disr_arg = BitCast(get_disr_bcx, get_disr_arg, llptrty);
let get_disr_ret = adt::trans_get_discr(get_disr_bcx, repr, get_disr_arg);
Store(get_disr_bcx, get_disr_ret, get_disr_fcx.llretptr);
cleanup_and_Br(get_disr_bcx, get_disr_bcx, get_disr_fcx.llreturn);
finish_fn(get_disr_fcx, get_disr_bcx.llbb);
let enum_args = ~[self.c_uint(vec::len(variants)),
get_disr_llfdecl]
+ self.c_size_and_align(t);
do self.bracketed(~"enum", enum_args) |this| {
for variants.eachi |i, v| {
@ -282,7 +305,7 @@ pub impl Reflector {
do this.bracketed(~"enum_variant", variant_args) |this| {
for v.args.eachi |j, a| {
let bcx = this.bcx;
let null = C_null(T_ptr(type_of(ccx, t)));
let null = C_null(llptrty);
let offset = p2i(ccx, adt::trans_field_ptr(bcx, repr, null,
v.disr_val, j));
let field_args = ~[this.c_uint(j),

View file

@ -13,7 +13,7 @@
use core::bool;
use core::libc::c_void;
use core::vec::UnboxedVecRepr;
use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor};
use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque};
#[doc = "High-level interfaces to `intrinsic::visit_ty` reflection system."]
@ -376,10 +376,12 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
true
}
fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint)
fn visit_enter_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
self.align(align);
if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; }
if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) { return false; }
true
}
@ -410,9 +412,11 @@ impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
true
}
fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint)
fn visit_leave_enum(&self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; }
if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { return false; }
true
}
@ -586,6 +590,7 @@ impl TyVisitor for my_visitor {
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_enum(&self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool {
// FIXME (#3732): this needs to rewind between enum variants, or something.
true
@ -602,6 +607,7 @@ impl TyVisitor for my_visitor {
_n_fields: uint,
_name: &str) -> bool { true }
fn visit_leave_enum(&self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_fn(&self, _purity: uint, _proto: uint,