about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-05-14 17:57:39 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-05-14 17:57:48 -0700
commite12b16cde7ecc4075a105f4e4b128f63c0c03c8d (patch)
treecb0ff9e62fef8270e618ceff32e249b723e3a26b /src/rustc
parent97aba0b14f965059a18f8e5ef8138dcfd5fe6293 (diff)
downloadrust-e12b16cde7ecc4075a105f4e4b128f63c0c03c8d.tar.gz
rust-e12b16cde7ecc4075a105f4e4b128f63c0c03c8d.zip
Instantiate per-type iface-based visit_glue when intrinsic ifaces present.
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/back/abi.rs2
-rw-r--r--src/rustc/middle/trans/base.rs41
-rw-r--r--src/rustc/middle/trans/common.rs8
-rw-r--r--src/rustc/middle/trans/native.rs76
-rw-r--r--src/rustc/middle/trans/reflect.rs93
-rw-r--r--src/rustc/rustc.rc1
6 files changed, 161 insertions, 60 deletions
diff --git a/src/rustc/back/abi.rs b/src/rustc/back/abi.rs
index 70606d9f885..3808621096f 100644
--- a/src/rustc/back/abi.rs
+++ b/src/rustc/back/abi.rs
@@ -39,7 +39,7 @@ const tydesc_field_align: uint = 2u;
 const tydesc_field_take_glue: uint = 3u;
 const tydesc_field_drop_glue: uint = 4u;
 const tydesc_field_free_glue: uint = 5u;
-const tydesc_field_unused: uint = 6u;
+const tydesc_field_visit_glue: uint = 6u;
 const tydesc_field_sever_glue: uint = 7u;
 const tydesc_field_mark_glue: uint = 8u;
 const tydesc_field_unused2: uint = 9u;
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 0136570a68a..769fee50d4f 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -470,7 +470,8 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
           align: llalign,
           mut take_glue: none,
           mut drop_glue: none,
-          mut free_glue: none};
+          mut free_glue: none,
+          mut visit_glue: none};
     log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
     ret inf;
 }
@@ -552,6 +553,11 @@ fn emit_tydescs(ccx: @crate_ctxt) {
               none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
               some(v) { ccx.stats.n_real_glues += 1u; v }
             };
+        let visit_glue =
+            alt ti.visit_glue {
+              none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
+              some(v) { ccx.stats.n_real_glues += 1u; v }
+            };
 
         let shape = shape_of(ccx, key, []);
         let shape_tables =
@@ -566,7 +572,7 @@ fn emit_tydescs(ccx: @crate_ctxt) {
                             take_glue, // take_glue
                             drop_glue, // drop_glue
                             free_glue, // free_glue
-                            C_null(T_ptr(T_i8())), // unused
+                            visit_glue, // visit_glue
                             C_null(glue_fn_ty), // sever_glue
                             C_null(glue_fn_ty), // mark_glue
                             C_null(glue_fn_ty), // unused
@@ -632,6 +638,20 @@ fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
     Store(cx, rc, rc_ptr);
 }
 
+fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
+    let _icx = bcx.insn_ctxt("make_visit_glue");
+    let mut bcx = bcx;
+    alt bcx.ccx().intrinsic_ifaces.find("visit_ty") {
+      some(iid) {
+        bcx = reflect::emit_calls_to_iface_visit_ty(bcx, t, v, iid);
+      }
+      none {
+      }
+    }
+    build_return(bcx);
+}
+
+
 fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
     // v is a pointer to the actual box component of the type here. The
     // ValueRef will have the wrong type here (make_generic_glue is casting
@@ -1065,7 +1085,23 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
                        ty_to_str(ccx.tcx, ti.ty));
               }
             }
+        } else if field == abi::tydesc_field_visit_glue {
+            alt ti.free_glue {
+              some(_) { }
+              none {
+                #debug("+++ lazily_emit_tydesc_glue VISIT %s",
+                       ty_to_str(ccx.tcx, ti.ty));
+                let glue_fn =
+                    declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "visit");
+                ti.visit_glue = some(glue_fn);
+                make_generic_glue(ccx, ti.ty, glue_fn,
+                                  make_visit_glue, "visit");
+                #debug("--- lazily_emit_tydesc_glue VISIT %s",
+                       ty_to_str(ccx.tcx, ti.ty));
+              }
+            }
         }
+
       }
     }
 }
@@ -5056,6 +5092,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           tn: tn,
           externs: str_hash::<ValueRef>(),
           intrinsics: intrinsics,
+          intrinsic_ifaces: reflect::find_intrinsic_ifaces(crate),
           item_vals: int_hash::<ValueRef>(),
           exp_map: emap,
           reachable: reachable,
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index 72e982ba445..ad2b86f395b 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -33,7 +33,8 @@ type tydesc_info =
      align: ValueRef,
      mut take_glue: option<ValueRef>,
      mut drop_glue: option<ValueRef>,
-     mut free_glue: option<ValueRef>};
+     mut free_glue: option<ValueRef>,
+     mut visit_glue: option<ValueRef>};
 
 /*
  * A note on nomenclature of linking: "upcall", "extern" and "native".
@@ -70,6 +71,7 @@ type crate_ctxt = {
      tn: type_names,
      externs: hashmap<str, ValueRef>,
      intrinsics: hashmap<str, ValueRef>,
+     intrinsic_ifaces: hashmap<str, ast::def_id>,
      item_vals: hashmap<ast::node_id, ValueRef>,
      exp_map: resolve::exp_map,
      reachable: reachable::map,
@@ -572,8 +574,8 @@ fn T_tydesc(targ_cfg: @session::config) -> TypeRef {
     let int_type = T_int(targ_cfg);
     let elems =
         [tydescpp, int_type, int_type,
-         glue_fn_ty, glue_fn_ty, glue_fn_ty,
-         T_ptr(T_i8()), glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()),
+         glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty,
+         glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()),
          T_ptr(T_i8()), T_ptr(T_i8()), int_type, int_type];
     set_struct_body(tydesc, elems);
     ret tydesc;
diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs
index f5b1a59d15f..ed5b769ce50 100644
--- a/src/rustc/middle/trans/native.rs
+++ b/src/rustc/middle/trans/native.rs
@@ -835,70 +835,38 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item,
               fcx.llretptr);
       }
       "visit_ty" {
-
-        // signature: fn visit_ty<T,V:ty_visitor>(tv: V);
-
         let tp_ty = substs.tys[0];
         let vp_ty = substs.tys[1];
         let visitor = get_param(decl, first_real_arg);
 
-        let (tyname, args) = alt ty::get(tp_ty).struct {
-          ty::ty_bot { ("bot", []) }
-          ty::ty_nil { ("nil", []) }
-          ty::ty_bool { ("bool", []) }
-          ty::ty_int(ast::ty_i) { ("int", []) }
-          ty::ty_int(ast::ty_char) { ("char", []) }
-          ty::ty_int(ast::ty_i8) { ("i8", []) }
-          ty::ty_int(ast::ty_i16) { ("i16", []) }
-          ty::ty_int(ast::ty_i32) { ("i32", []) }
-          ty::ty_int(ast::ty_i64) { ("i64", []) }
-          ty::ty_uint(ast::ty_u) { ("uint", []) }
-          ty::ty_uint(ast::ty_u8) { ("u8", []) }
-          ty::ty_uint(ast::ty_u16) { ("u16", []) }
-          ty::ty_uint(ast::ty_u32) { ("u32", []) }
-          ty::ty_uint(ast::ty_u64) { ("u64", []) }
-          ty::ty_float(ast::ty_f) { ("float", []) }
-          ty::ty_float(ast::ty_f32) { ("f32", []) }
-          ty::ty_float(ast::ty_f64) { ("f64", []) }
-          ty::ty_str { ("str", []) }
-          _ {
-            bcx.sess().unimpl("trans::native::visit_ty on "
-                              + ty_to_str(ccx.tcx, tp_ty));
-          }
-        };
-
-        let mth_name = "visit_" + tyname;
-        let dest = ignore;
-
         alt impl::find_vtable_in_fn_ctxt(substs,
                                          1u, /* n_param */
                                          0u  /* n_bound */ ) {
 
-          typeck::vtable_static(impl_did, impl_substs, sub_origins) {
-            let mth_id = impl::method_with_name(ccx, impl_did, mth_name);
-            let mth_ty = ty::lookup_item_type(ccx.tcx, mth_id).ty;
-            // FIXME: is this safe? There is no callee AST node,
-            // we're synthesizing it.
-            let callee_id = (-1) as ast::node_id;
-            let get_lval = {|bcx|
-                let lval = lval_static_fn_inner(bcx, mth_id, callee_id,
-                                                impl_substs,
-                                                some(sub_origins));
-                {env: self_env(visitor, vp_ty, none) with lval}
-            };
-            bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx),
-                                   get_lval, arg_vals(args), dest);
+          typeck::vtable_iface(iid, _) {
+            bcx = reflect::emit_calls_to_iface_visit_ty(bcx, tp_ty,
+                                                        visitor, iid);
           }
 
-          typeck::vtable_iface(iid, _tps) {
-            let methods = ty::iface_methods(ccx.tcx, iid);
-            let mth_idx = option::get(ty::method_idx(mth_name, *methods));
-            let mth_ty = ty::mk_fn(ccx.tcx, methods[mth_idx].fty);
-            let get_lval = {|bcx|
-                impl::trans_iface_callee(bcx, visitor, mth_ty, mth_idx)
-            };
-            bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx),
-                                   get_lval, arg_vals(args), dest);
+          // This case is a slightly weird and possibly redundant path in
+          // which we monomorphize the reflection interface.  FIXME:
+          // possibly remove this, it might be overkill.
+          typeck::vtable_static(impl_did, impl_substs, sub_origins) {
+            reflect::visit_ty_steps(bcx, tp_ty) {|mth_name, args|
+                let mth_id = impl::method_with_name(ccx, impl_did, mth_name);
+                let mth_ty = ty::lookup_item_type(ccx.tcx, mth_id).ty;
+                // FIXME: is this safe? There is no callee AST node,
+                // we're synthesizing it.
+                let callee_id = (-1) as ast::node_id;
+                let get_lval = {|bcx|
+                    let lval = lval_static_fn_inner(bcx, mth_id, callee_id,
+                                                    impl_substs,
+                                                    some(sub_origins));
+                    {env: self_env(visitor, vp_ty, none) with lval}
+                };
+                bcx = trans_call_inner(bcx, mth_ty, ty::mk_bool(ccx.tcx),
+                                       get_lval, arg_vals(args), ignore);
+            }
           }
 
           _ {
diff --git a/src/rustc/middle/trans/reflect.rs b/src/rustc/middle/trans/reflect.rs
new file mode 100644
index 00000000000..b1650ef465b
--- /dev/null
+++ b/src/rustc/middle/trans/reflect.rs
@@ -0,0 +1,93 @@
+import std::map::{hashmap,str_hash};
+import driver::session::session;
+import lib::llvm::{TypeRef, ValueRef};
+import syntax::ast;
+import back::abi;
+import common::*;
+import build::*;
+import base::*;
+import type_of::*;
+import ast::def_id;
+import util::ppaux::ty_to_str;
+
+fn visit_ty_steps<T>(bcx: block, t: ty::t,
+                     step: fn(tyname: str, args: [ValueRef]) -> T) -> T {
+    alt ty::get(t).struct {
+      ty::ty_bot { step("visit_bot", []) }
+      ty::ty_nil { step("visit_nil", []) }
+      ty::ty_bool { step("visit_bool", []) }
+      ty::ty_int(ast::ty_i) { step("visit_int", []) }
+      ty::ty_int(ast::ty_char) { step("visit_char", []) }
+          ty::ty_int(ast::ty_i8) { step("visit_i8", []) }
+          ty::ty_int(ast::ty_i16) { step("visit_i16", []) }
+          ty::ty_int(ast::ty_i32) { step("visit_i32", []) }
+          ty::ty_int(ast::ty_i64) { step("visit_i64", []) }
+          ty::ty_uint(ast::ty_u) { step("visit_uint", []) }
+          ty::ty_uint(ast::ty_u8) { step("visit_u8", []) }
+          ty::ty_uint(ast::ty_u16) { step("visit_u16", []) }
+          ty::ty_uint(ast::ty_u32) { step("visit_u32", []) }
+          ty::ty_uint(ast::ty_u64) { step("visit_u64", []) }
+          ty::ty_float(ast::ty_f) { step("visit_float", []) }
+          ty::ty_float(ast::ty_f32) { step("visit_f32", []) }
+          ty::ty_float(ast::ty_f64) { step("visit_f64", []) }
+          ty::ty_str { step("visit_str", []) }
+      _ {
+        bcx.sess().unimpl("trans::reflect::visit_ty_args on "
+                          + ty_to_str(bcx.ccx().tcx, t));
+      }
+    }
+}
+
+// Emit a sequence of calls to visit_ty::visit_foo
+fn emit_calls_to_iface_visit_ty(bcx: block, t: ty::t,
+                                visitor_val: ValueRef,
+                                visitor_iid: def_id) -> block {
+    let tcx = bcx.tcx();
+    visit_ty_steps(bcx, t) {|mth_name, args|
+        let methods = ty::iface_methods(tcx, visitor_iid);
+        let mth_idx = option::get(ty::method_idx(mth_name, *methods));
+        let mth_ty = ty::mk_fn(tcx, methods[mth_idx].fty);
+        let get_lval = {|bcx|
+            impl::trans_iface_callee(bcx, visitor_val, mth_ty, mth_idx)
+        };
+        trans_call_inner(bcx, mth_ty, ty::mk_bool(tcx),
+                         get_lval, arg_vals(args), ignore)
+    }
+}
+
+
+fn find_intrinsic_ifaces(crate: @ast::crate)
+    -> hashmap<str, ast::def_id> {
+
+    let ifaces : hashmap<str, ast::def_id> = str_hash();
+
+    // FIXME: hooking into the "intrinsic" root module is crude.
+    // there ought to be a better approach. Attributes?
+
+    for crate.node.module.items.each {|crate_item|
+        if crate_item.ident == "intrinsic" {
+            alt crate_item.node {
+              ast::item_mod(m) {
+                for m.items.each {|intrinsic_item|
+                    alt intrinsic_item.node {
+                      ast::item_iface(_, _, _) {
+                        let def_id = { crate: ast::local_crate,
+                                       node: intrinsic_item.id };
+                        ifaces.insert(intrinsic_item.ident,
+                                      def_id);
+                      }
+                      _ { }
+                    }
+                }
+              }
+              _ { }
+            }
+            break;
+        }
+    }
+
+    // Assert whatever ifaces we are expecting to get from mod intrinsic.
+    // assert ifaces.contains_key("visit_ty");
+
+    ret ifaces;
+}
\ No newline at end of file
diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc
index 41635f8fec7..21623f45f5c 100644
--- a/src/rustc/rustc.rc
+++ b/src/rustc/rustc.rc
@@ -42,6 +42,7 @@ mod middle {
         mod tvec;
         mod impl;
         mod native;
+        mod reflect;
         mod shape;
         mod debuginfo;
         mod type_use;