Skip to content

Commit 3809a04

Browse files
committed
auto merge of #5778 : jld/rust/reflect-abstract-enum, r=graydon
This takes care of one of the last remnants of assumptions about enum layout. A type visitor is now passed a function to read a value's discriminant, then accesses fields by being passed a byte offset for each one. The latter may not be fully general, despite the constraints imposed on representations by borrowed pointers, but works for any representations currently planned and is relatively simple. Closes #5652.
2 parents 7b152ba + e9a52f5 commit 3809a04

File tree

5 files changed

+201
-28
lines changed

5 files changed

+201
-28
lines changed

src/libcore/reflect.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Runtime type reflection
1515
*/
1616

1717
use intrinsic::{TyDesc, TyVisitor};
18+
#[cfg(not(stage0))] use intrinsic::Opaque;
1819
use libc::c_void;
1920
use sys;
2021
use vec;
@@ -393,6 +394,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
393394
true
394395
}
395396

397+
#[cfg(stage0)]
396398
fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint)
397399
-> bool {
398400
self.align(align);
@@ -402,25 +404,47 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
402404
true
403405
}
404406

407+
#[cfg(not(stage0))]
408+
fn visit_enter_enum(&self, n_variants: uint,
409+
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
410+
sz: uint, align: uint)
411+
-> bool {
412+
self.align(align);
413+
if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
414+
return false;
415+
}
416+
true
417+
}
418+
405419
fn visit_enter_enum_variant(&self, variant: uint,
406420
disr_val: int,
407421
n_fields: uint,
408422
name: &str) -> bool {
409-
self.inner.push_ptr();
423+
self.inner.push_ptr(); // NOTE remove after next snapshot
410424
if ! self.inner.visit_enter_enum_variant(variant, disr_val,
411425
n_fields, name) {
412426
return false;
413427
}
414428
true
415429
}
416430

431+
#[cfg(stage0)]
417432
fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
418433
unsafe { self.align((*inner).align); }
419434
if ! self.inner.visit_enum_variant_field(i, inner) { return false; }
420435
unsafe { self.bump((*inner).size); }
421436
true
422437
}
423438

439+
#[cfg(not(stage0))]
440+
fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
441+
self.inner.push_ptr();
442+
self.bump(offset);
443+
if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
444+
self.inner.pop_ptr();
445+
true
446+
}
447+
424448
fn visit_leave_enum_variant(&self, variant: uint,
425449
disr_val: int,
426450
n_fields: uint,
@@ -429,10 +453,11 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
429453
n_fields, name) {
430454
return false;
431455
}
432-
self.inner.pop_ptr();
456+
self.inner.pop_ptr(); // NOTE remove after next snapshot
433457
true
434458
}
435459

460+
#[cfg(stage0)]
436461
fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint)
437462
-> bool {
438463
if ! self.inner.visit_leave_enum(n_variants, sz, align) {
@@ -442,6 +467,17 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
442467
true
443468
}
444469

470+
#[cfg(not(stage0))]
471+
fn visit_leave_enum(&self, n_variants: uint,
472+
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
473+
sz: uint, align: uint) -> bool {
474+
if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
475+
return false;
476+
}
477+
self.bump(sz);
478+
true
479+
}
480+
445481
fn visit_trait(&self) -> bool {
446482
self.align_to::<@TyVisitor>();
447483
if ! self.inner.visit_trait() { return false; }

src/libcore/repr.rs

+96-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use cast::transmute;
1818
use char;
1919
use intrinsic;
2020
use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
21+
#[cfg(not(stage0))] use intrinsic::Opaque;
2122
use io::{Writer, WriterUtil};
2223
use libc::c_void;
2324
use managed;
@@ -137,12 +138,20 @@ impl Repr for char {
137138

138139
// New implementation using reflect::MovePtr
139140

141+
#[cfg(stage0)]
140142
enum VariantState {
141143
Degenerate,
142144
TagMatch,
143145
TagMismatch,
144146
}
145147

148+
#[cfg(not(stage0))]
149+
enum VariantState {
150+
SearchingFor(int),
151+
Matched,
152+
AlreadyFound
153+
}
154+
146155
pub struct ReprVisitor {
147156
mut ptr: *c_void,
148157
mut ptr_stk: ~[*c_void],
@@ -181,14 +190,14 @@ pub impl ReprVisitor {
181190
true
182191
}
183192

184-
#[inline(always)]
193+
#[cfg(stage0)] #[inline(always)]
185194
fn bump(&self, sz: uint) {
186195
do self.move_ptr() |p| {
187196
((p as uint) + sz) as *c_void
188197
};
189198
}
190199

191-
#[inline(always)]
200+
#[cfg(stage0)] #[inline(always)]
192201
fn bump_past<T>(&self) {
193202
self.bump(sys::size_of::<T>());
194203
}
@@ -458,6 +467,7 @@ impl TyVisitor for ReprVisitor {
458467
true
459468
}
460469

470+
#[cfg(stage0)]
461471
fn visit_enter_enum(&self, n_variants: uint,
462472
_sz: uint, _align: uint) -> bool {
463473
if n_variants == 1 {
@@ -468,6 +478,16 @@ impl TyVisitor for ReprVisitor {
468478
true
469479
}
470480

481+
#[cfg(not(stage0))]
482+
fn visit_enter_enum(&self, n_variants: uint,
483+
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
484+
_sz: uint, _align: uint) -> bool {
485+
let disr = unsafe { get_disr(transmute(self.ptr)) };
486+
self.var_stk.push(SearchingFor(disr));
487+
true
488+
}
489+
490+
#[cfg(stage0)]
471491
fn visit_enter_enum_variant(&self, _variant: uint,
472492
disr_val: int,
473493
n_fields: uint,
@@ -500,6 +520,36 @@ impl TyVisitor for ReprVisitor {
500520
true
501521
}
502522

523+
#[cfg(not(stage0))]
524+
fn visit_enter_enum_variant(&self, _variant: uint,
525+
disr_val: int,
526+
n_fields: uint,
527+
name: &str) -> bool {
528+
let mut write = false;
529+
match self.var_stk.pop() {
530+
SearchingFor(sought) => {
531+
if disr_val == sought {
532+
self.var_stk.push(Matched);
533+
write = true;
534+
} else {
535+
self.var_stk.push(SearchingFor(sought));
536+
}
537+
}
538+
Matched | AlreadyFound => {
539+
self.var_stk.push(AlreadyFound);
540+
}
541+
}
542+
543+
if write {
544+
self.writer.write_str(name);
545+
if n_fields > 0 {
546+
self.writer.write_char('(');
547+
}
548+
}
549+
true
550+
}
551+
552+
#[cfg(stage0)]
503553
fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
504554
match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
505555
Degenerate | TagMatch => {
@@ -515,6 +565,23 @@ impl TyVisitor for ReprVisitor {
515565
true
516566
}
517567

568+
#[cfg(not(stage0))]
569+
fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool {
570+
match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
571+
Matched => {
572+
if i != 0 {
573+
self.writer.write_str(", ");
574+
}
575+
if ! self.visit_inner(inner) {
576+
return false;
577+
}
578+
}
579+
_ => ()
580+
}
581+
true
582+
}
583+
584+
#[cfg(stage0)]
518585
fn visit_leave_enum_variant(&self, _variant: uint,
519586
_disr_val: int,
520587
n_fields: uint,
@@ -530,12 +597,39 @@ impl TyVisitor for ReprVisitor {
530597
true
531598
}
532599

600+
#[cfg(not(stage0))]
601+
fn visit_leave_enum_variant(&self, _variant: uint,
602+
_disr_val: int,
603+
n_fields: uint,
604+
_name: &str) -> bool {
605+
match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
606+
Matched => {
607+
if n_fields > 0 {
608+
self.writer.write_char(')');
609+
}
610+
}
611+
_ => ()
612+
}
613+
true
614+
}
615+
616+
#[cfg(stage0)]
533617
fn visit_leave_enum(&self, _n_variants: uint,
534618
_sz: uint, _align: uint) -> bool {
535619
self.var_stk.pop();
536620
true
537621
}
538622

623+
#[cfg(not(stage0))]
624+
fn visit_leave_enum(&self, _n_variants: uint,
625+
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
626+
_sz: uint, _align: uint) -> bool {
627+
match self.var_stk.pop() {
628+
SearchingFor(*) => fail!(~"enum value matched no variant"),
629+
_ => true
630+
}
631+
}
632+
539633
fn visit_enter_fn(&self, _purity: uint, _proto: uint,
540634
_n_inputs: uint, _retstyle: uint) -> bool { true }
541635
fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {

src/librustc/front/intrinsic.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub mod intrinsic {
2828
// Remaining fields not listed
2929
}
3030

31+
pub enum Opaque { }
32+
3133
pub trait TyVisitor {
3234
fn visit_bot(&self) -> bool;
3335
fn visit_nil(&self) -> bool;
@@ -91,17 +93,19 @@ pub mod intrinsic {
9193
sz: uint, align: uint) -> bool;
9294

9395
fn visit_enter_enum(&self, n_variants: uint,
96+
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
9497
sz: uint, align: uint) -> bool;
9598
fn visit_enter_enum_variant(&self, variant: uint,
9699
disr_val: int,
97100
n_fields: uint,
98101
name: &str) -> bool;
99-
fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool;
102+
fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool;
100103
fn visit_leave_enum_variant(&self, variant: uint,
101104
disr_val: int,
102105
n_fields: uint,
103106
name: &str) -> bool;
104107
fn visit_leave_enum(&self, n_variants: uint,
108+
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
105109
sz: uint, align: uint) -> bool;
106110

107111
fn visit_enter_fn(&self, purity: uint, proto: uint,

src/librustc/middle/trans/reflect.rs

+48-15
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
12-
use lib::llvm::{TypeRef, ValueRef};
11+
use back::link::mangle_internal_name_by_path_and_seq;
12+
use lib::llvm::{TypeRef, ValueRef, llvm};
13+
use middle::trans::adt;
1314
use middle::trans::base::*;
1415
use middle::trans::build::*;
1516
use middle::trans::callee::{ArgVals, DontAutorefArg};
@@ -24,10 +25,13 @@ use middle::trans::type_of::*;
2425
use middle::ty;
2526
use util::ppaux::ty_to_str;
2627

28+
use core::libc::c_uint;
2729
use core::option::None;
2830
use core::vec;
2931
use syntax::ast::def_id;
3032
use syntax::ast;
33+
use syntax::ast_map::path_name;
34+
use syntax::parse::token::special_idents;
3135

3236
pub struct Reflector {
3337
visitor_val: ValueRef,
@@ -266,23 +270,52 @@ pub impl Reflector {
266270
// variant?
267271
ty::ty_enum(did, ref substs) => {
268272
let bcx = self.bcx;
269-
let tcx = bcx.ccx().tcx;
270-
let variants = ty::substd_enum_variants(tcx, did, substs);
273+
let ccx = bcx.ccx();
274+
let repr = adt::represent_type(bcx.ccx(), t);
275+
let variants = ty::substd_enum_variants(ccx.tcx, did, substs);
276+
let llptrty = T_ptr(type_of(ccx, t));
277+
let (_, opaquety) = *(ccx.tcx.intrinsic_defs.find(&ccx.sess.ident_of(~"Opaque"))
278+
.expect("Failed to resolve intrinsic::Opaque"));
279+
let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm });
280+
281+
let make_get_disr = || {
282+
let sub_path = bcx.fcx.path + ~[path_name(special_idents::anon)];
283+
let sym = mangle_internal_name_by_path_and_seq(ccx, sub_path, ~"get_disr");
284+
let args = [ty::arg { mode: ast::expl(ast::by_copy),
285+
ty: opaqueptrty }];
286+
let llfty = type_of_fn(ccx, args, ty::mk_int(ccx.tcx));
287+
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
288+
let arg = unsafe {
289+
llvm::LLVMGetParam(llfdecl, first_real_arg as c_uint)
290+
};
291+
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None);
292+
let bcx = top_scope_block(fcx, None);
293+
let arg = BitCast(bcx, arg, llptrty);
294+
let ret = adt::trans_get_discr(bcx, repr, arg);
295+
Store(bcx, ret, fcx.llretptr);
296+
cleanup_and_Br(bcx, bcx, fcx.llreturn);
297+
finish_fn(fcx, bcx.llbb);
298+
llfdecl
299+
};
271300

272-
let extra = ~[self.c_uint(vec::len(variants))]
301+
let enum_args = ~[self.c_uint(vec::len(variants)), make_get_disr()]
273302
+ self.c_size_and_align(t);
274-
do self.bracketed(~"enum", extra) |this| {
303+
do self.bracketed(~"enum", enum_args) |this| {
275304
for variants.eachi |i, v| {
276-
let extra1 = ~[this.c_uint(i),
277-
this.c_int(v.disr_val),
278-
this.c_uint(vec::len(v.args)),
279-
this.c_slice(
280-
bcx.ccx().sess.str_of(v.name))];
281-
do this.bracketed(~"enum_variant", extra1) |this| {
305+
let variant_args = ~[this.c_uint(i),
306+
this.c_int(v.disr_val),
307+
this.c_uint(vec::len(v.args)),
308+
this.c_slice(ccx.sess.str_of(v.name))];
309+
do this.bracketed(~"enum_variant", variant_args) |this| {
282310
for v.args.eachi |j, a| {
283-
let extra = ~[this.c_uint(j),
284-
this.c_tydesc(*a)];
285-
this.visit(~"enum_variant_field", extra);
311+
let bcx = this.bcx;
312+
let null = C_null(llptrty);
313+
let offset = p2i(ccx, adt::trans_field_ptr(bcx, repr, null,
314+
v.disr_val, j));
315+
let field_args = ~[this.c_uint(j),
316+
offset,
317+
this.c_tydesc(*a)];
318+
this.visit(~"enum_variant_field", field_args);
286319
}
287320
}
288321
}

0 commit comments

Comments
 (0)