about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2012-03-08 16:10:25 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-03-15 09:26:54 +0100
commit4511f936b1b4766962d01a80f6887eecb30e89f9 (patch)
tree48b28b06700535ea112e7c8ea78dc088b7c2885d
parent168398bb3dc01f8efecf734342af60a959a74b8d (diff)
downloadrust-4511f936b1b4766962d01a80f6887eecb30e89f9.tar.gz
rust-4511f936b1b4766962d01a80f6887eecb30e89f9.zip
Hugely simplify iface handling
With the assumption of monomorphization
-rw-r--r--src/rustc/metadata/astencode.rs8
-rw-r--r--src/rustc/metadata/decoder.rs2
-rw-r--r--src/rustc/middle/trans/base.rs68
-rw-r--r--src/rustc/middle/trans/closure.rs24
-rw-r--r--src/rustc/middle/trans/common.rs29
-rw-r--r--src/rustc/middle/trans/impl.rs311
-rw-r--r--src/rustc/middle/ty.rs9
-rw-r--r--src/rustc/middle/typeck.rs6
8 files changed, 136 insertions, 321 deletions
diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs
index 45b3355f009..40900e755b9 100644
--- a/src/rustc/metadata/astencode.rs
+++ b/src/rustc/metadata/astencode.rs
@@ -548,11 +548,14 @@ fn encode_dict_origin(ecx: @e::encode_ctxt,
                 }
             }
           }
-          typeck::dict_iface(def_id) {
+          typeck::dict_iface(def_id, tys) {
             ebml_w.emit_enum_variant("dict_iface", 1u, 3u) {||
                 ebml_w.emit_enum_variant_arg(0u) {||
                     ebml_w.emit_def_id(def_id)
                 }
+                ebml_w.emit_enum_variant_arg(1u) {||
+                    ebml_w.emit_tys(ecx, tys);
+                }
             }
           }
         }
@@ -596,6 +599,9 @@ impl helpers for ebml::ebml_deserializer {
                     typeck::dict_iface(
                         self.read_enum_variant_arg(0u) {||
                             self.read_def_id(xcx)
+                        },
+                        self.read_enum_variant_arg(1u) {||
+                            self.read_tys(xcx)
                         }
                     )
                   }
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index f7120f0efc2..f78c0ade6f1 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -258,7 +258,7 @@ fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
 }
 
 fn get_impl_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
-    let items = ebml::get_doc(ebml::new_doc(cdata.data), tag_items);
+    let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
     let found = none;
     ebml::tagged_docs(find_item(id, items), tag_item_method) {|mid|
         let m_did = parse_def_id(ebml::doc_data(mid));
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index ab8855ff247..e87e79be922 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2070,7 +2070,6 @@ enum callee_env {
     null_env,
     is_closure,
     self_env(ValueRef, ty::t),
-    dict_env(ValueRef, ValueRef),
 }
 type lval_maybe_callee = {bcx: block,
                           val: ValueRef,
@@ -2117,8 +2116,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
         }
     });
     let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts {
-      some(os) { vec::map(*os, {|o| impl::dict_id(ccx.tcx, o)}) }
-      none { [] }
+      some(os) { some_dicts(vec::map(*os, impl::vtable_id)) }
+      none { no_dicts }
     }};
     alt ccx.monomorphized.find(hash_id) {
       some(val) { ret some(val); }
@@ -2258,10 +2257,8 @@ fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
           none {
             alt ccx.maps.dict_map.find(id) {
               some(dicts) {
-                alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) {
-                  some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) }
-                  none { none }
-                }
+                let rdicts = impl::resolve_vtables_in_fn_ctxt(bcx.fcx, dicts);
+                monomorphic_fn(ccx, fn_id, tys, some(rdicts))
               }
               none { monomorphic_fn(ccx, fn_id, tys, none) }
             }
@@ -2567,7 +2564,7 @@ fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
 
 fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
     let must_bind = alt c.generic { generic_full(_) { true } _ { false } } ||
-        alt c.env { self_env(_, _) | dict_env(_, _) { true } _ { false } };
+        alt c.env { self_env(_, _) { true } _ { false } };
     if must_bind {
         let n_args = ty::ty_fn_args(ty).len();
         let args = vec::from_elem(n_args, none);
@@ -2779,28 +2776,7 @@ fn trans_args(cx: block, llenv: ValueRef,
 
     let retty = ty::ty_fn_ret(fn_ty), full_retty = retty;
     alt gen {
-      generic_full(g) {
-        lazily_emit_all_generic_info_tydesc_glues(ccx, g);
-        let i = 0u, n_orig = 0u;
-        for param in *g.param_bounds {
-            lltydescs += [g.tydescs[i]];
-            for bound in *param {
-                alt bound {
-                  ty::bound_iface(_) {
-                    let res = impl::get_dict(
-                        bcx, option::get(g.origins)[n_orig]);
-                    lltydescs += [res.val];
-                    bcx = res.bcx;
-                    n_orig += 1u;
-                  }
-                  _ {}
-                }
-            }
-            i += 1u;
-        }
-        args = ty::ty_fn_args(g.item_type);
-        retty = ty::ty_fn_ret(g.item_type);
-      }
+      generic_full(g) { fail; }
       generic_mono(t) {
         args = ty::ty_fn_args(t);
         retty = ty::ty_fn_ret(t);
@@ -2884,17 +2860,12 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
         let bcx = f_res.bcx, ccx = cx.ccx();
 
         let faddr = f_res.val;
-        let llenv, dict_param = none;
-        alt f_res.env {
+        let llenv = alt f_res.env {
           null_env {
-            llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(ccx));
+            llvm::LLVMGetUndef(T_opaque_box_ptr(ccx))
           }
           self_env(e, _) {
-            llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
-          }
-          dict_env(dict, e) {
-            llenv = PointerCast(bcx, e, T_opaque_box_ptr(ccx));
-            dict_param = some(dict);
+            PointerCast(bcx, e, T_opaque_box_ptr(ccx))
           }
           is_closure {
             // It's a closure. Have to fetch the elements
@@ -2905,16 +2876,15 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t,
             faddr = GEPi(bcx, pair, [0, abi::fn_field_code]);
             faddr = Load(bcx, faddr);
             let llclosure = GEPi(bcx, pair, [0, abi::fn_field_box]);
-            llenv = Load(bcx, llclosure);
+            Load(bcx, llclosure)
           }
-        }
+        };
 
         let ret_ty = node_id_type(bcx, id);
         let args_res =
             trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
         bcx = args_res.bcx;
         let llargs = args_res.args;
-        option::may(dict_param) {|dict| llargs = [dict] + llargs}
         let llretslot = args_res.retslot;
 
         /* If the block is terminated,
@@ -2955,6 +2925,10 @@ fn invoke_(bcx: block, llfn: ValueRef, llargs: [ValueRef],
     // cleanups to run
     if bcx.unreachable { ret bcx; }
     let normal_bcx = sub_block(bcx, "normal return");
+    /*std::io::println("fn: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(llfn)));
+    for a in llargs {
+        std::io::println(" a: " + lib::llvm::type_to_str(bcx.ccx().tn, val_ty(a)));
+    }*/
     invoker(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
     ret normal_bcx;
 }
@@ -4791,16 +4765,6 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
             i += 1;
         }
       }
-      ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
-        let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
-        impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
-      }
-      ast::item_iface(_, _) {
-        if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m|
-            ty::type_has_vars(ty::mk_fn(ccx.tcx, m.fty))}) {
-            impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
-        }
-      }
       _ { }
     }
 }
@@ -5032,9 +4996,9 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           discrims: ast_util::new_def_id_hash::<ValueRef>(),
           discrim_symbols: int_hash::<str>(),
           tydescs: ty::new_ty_hash(),
-          dicts: map::hashmap(hash_dict_id, {|a, b| a == b}),
           external: util::common::new_def_hash(),
           monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
+          vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
           module_data: str_hash::<ValueRef>(),
           lltypes: ty::new_ty_hash(),
           names: new_namegen(),
diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs
index bdc97206ec2..63a3c067c5c 100644
--- a/src/rustc/middle/trans/closure.rs
+++ b/src/rustc/middle/trans/closure.rs
@@ -515,26 +515,7 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
 
     // Figure out which tydescs we need to pass, if any.
     let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
-      generic_full(ginfo) {
-        let tds = [], orig = 0u;
-        vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds|
-            tds += [td];
-            for bound in *bounds {
-                alt bound {
-                  ty::bound_iface(_) {
-                    let dict = impl::get_dict(
-                        bcx, option::get(ginfo.origins)[orig]);
-                    tds += [PointerCast(bcx, dict.val, val_ty(td))];
-                    orig += 1u;
-                    bcx = dict.bcx;
-                  }
-                  _ {}
-                }
-            }
-        }
-        lazily_emit_all_generic_info_tydesc_glues(ccx, ginfo);
-        (ginfo.item_type, tds, ginfo.param_bounds)
-      }
+      generic_full(ginfo) { fail; }
       _ { (outgoing_fty, [], @[]) }
     };
 
@@ -560,9 +541,6 @@ fn trans_bind_1(cx: block, outgoing_fty: ty::t,
       self_env(slf, slf_t) {
         ([env_copy(slf, slf_t, owned)], target_self(f_res.val))
       }
-      dict_env(_, _) {
-        ccx.sess.unimpl("binding of dynamic method calls");
-      }
     };
 
     // Actually construct the closure
diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs
index 5f0dda5267c..7ee791f6213 100644
--- a/src/rustc/middle/trans/common.rs
+++ b/src/rustc/middle/trans/common.rs
@@ -90,11 +90,12 @@ type crate_ctxt = {
      discrims: hashmap<ast::def_id, ValueRef>,
      discrim_symbols: hashmap<ast::node_id, str>,
      tydescs: hashmap<ty::t, @tydesc_info>,
-     dicts: hashmap<dict_id, ValueRef>,
      // Track mapping of external ids to local items imported for inlining
      external: hashmap<ast::def_id, option<ast::node_id>>,
      // Cache instances of monomorphized functions
      monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>,
+     // Cache generated vtables
+     vtables: hashmap<mono_id, ValueRef>,
      module_data: hashmap<str, ValueRef>,
      lltypes: hashmap<ty::t, TypeRef>,
      names: namegen,
@@ -846,30 +847,16 @@ pure fn type_has_static_size(cx: @crate_ctxt, t: ty::t) -> bool {
     !ty::type_has_dynamic_size(cx.tcx, t)
 }
 
-// Used to identify cached dictionaries
-enum dict_param {
-    dict_param_dict(dict_id),
-    dict_param_ty(ty::t),
-}
-type dict_id = @{def: ast::def_id, params: [dict_param]};
-fn hash_dict_id(&&dp: dict_id) -> uint {
-    let h = syntax::ast_util::hash_def_id(dp.def);
-    for param in dp.params {
-        h = h << 2u;
-        alt param {
-          dict_param_dict(d) { h += hash_dict_id(d); }
-          dict_param_ty(t) { h += ty::type_id(t); }
-        }
-    }
-    h
-}
-
 // Used to identify cached monomorphized functions
-type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: [dict_id]};
+enum mono_dicts { some_dicts([mono_id]), no_dicts }
+type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: mono_dicts};
 fn hash_mono_id(&&mi: mono_id) -> uint {
     let h = syntax::ast_util::hash_def_id(mi.def);
     for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); }
-    for dict in mi.dicts { h = (h << 2u) + hash_dict_id(dict); }
+    alt mi.dicts {
+      some_dicts(ds) { for d in ds { h = (h << 2u) + hash_mono_id(d); } }
+      _ {}
+    }
     h
 }
 
diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs
index 161256d5235..ad37fee317c 100644
--- a/src/rustc/middle/trans/impl.rs
+++ b/src/rustc/middle/trans/impl.rs
@@ -14,36 +14,6 @@ import lib::llvm::llvm::LLVMGetParam;
 import ast_map::{path, path_mod, path_name};
 import std::map::hashmap;
 
-// Translation functionality related to impls and ifaces
-//
-// Terminology:
-//  vtable:  a table of function pointers pointing to method wrappers
-//           of an impl that implements an iface
-//  dict:    a record containing a vtable pointer along with pointers to
-//           all tydescs and other dicts needed to run methods in this vtable
-//           (i.e. corresponding to the type parameters of the impl)
-//  wrapper: a function that takes a dict as first argument, along
-//           with the method-specific tydescs for a method (and all
-//           other args the method expects), which fetches the extra
-//           tydescs and dicts from the dict, splices them into the
-//           arglist, and calls through to the actual method
-//
-// Generic functions take, along with their normal arguments, a number
-// of extra tydesc and dict arguments -- one tydesc for each type
-// parameter, one dict (following the tydesc in the arg order) for
-// each interface bound on a type parameter.
-//
-// Most dicts are completely static, and are allocated and filled at
-// compile time. Dicts that depend on run-time values (tydescs or
-// dicts for type parameter types) are built at run-time, and interned
-// through upcall_intern_dict in the runtime. This means that dict
-// pointers are self-contained things that do not need to be cleaned
-// up.
-//
-// The trans_constants pass in trans.rs outputs the vtables. Typeck
-// annotates nodes with information about the methods and dicts that
-// are referenced (ccx.method_map and ccx.dict_map).
-
 fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
               methods: [@ast::method], tps: [ast::ty_param]) {
     if tps.len() > 0u { ret; }
@@ -81,18 +51,15 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
         trans_static_callee(bcx, callee_id, self, did, none)
       }
       typeck::method_param(iid, off, p, b) {
-        alt bcx.fcx.param_substs {
+        alt check bcx.fcx.param_substs {
           some(substs) {
             trans_monomorphized_callee(bcx, callee_id, self,
                                        iid, off, p, b, substs)
           }
-          none {
-            trans_param_callee(bcx, callee_id, self, iid, off, p, b)
-          }
         }
       }
-      typeck::method_iface(iid, off) {
-        trans_iface_callee(bcx, callee_id, self, iid, off)
+      typeck::method_iface(_, off) {
+        trans_iface_callee(bcx, self, callee_id, off)
       }
     }
 }
@@ -115,39 +82,20 @@ fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
 }
 
 fn trans_vtable_callee(bcx: block, env: callee_env, dict: ValueRef,
-                       callee_id: ast::node_id, iface_id: ast::def_id,
-                       n_method: uint) -> lval_maybe_callee {
+                       callee_id: ast::node_id, n_method: uint)
+    -> lval_maybe_callee {
     let bcx = bcx, ccx = bcx.ccx(), tcx = ccx.tcx;
-    let method = ty::iface_methods(tcx, iface_id)[n_method];
-    let method_ty = ty::mk_fn(tcx, method.fty);
-    let {ty: fty, llty: llfty} =
-        wrapper_fn_ty(ccx, val_ty(dict), method_ty, method.tps);
-    let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
+    let fty = node_id_type(bcx, callee_id);
+    let llfty = type_of::type_of_fn_from_ty(ccx, fty, []);
+    let vtable = PointerCast(bcx, dict,
                              T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
     let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
-    let generic = generic_none;
-    if (*method.tps).len() > 0u || ty::type_has_params(fty) {
-        let tydescs = [], tis = [];
-        let tptys = node_id_type_params(bcx, callee_id);
-        for t in vec::tailn(tptys, tptys.len() - (*method.tps).len()) {
-            let ti = none;
-            let td = get_tydesc(bcx, t, true, ti);
-            tis += [ti];
-            tydescs += [td.val];
-            bcx = td.bcx;
-        }
-        generic = generic_full({item_type: fty,
-                                static_tis: tis,
-                                tydescs: tydescs,
-                                param_bounds: method.tps,
-                                origins: ccx.maps.dict_map.find(callee_id)});
-    }
     {bcx: bcx, val: mptr, kind: owned,
      env: env,
-     generic: generic}
+     generic: generic_none}
 }
 
-fn method_with_name(ccx: crate_ctxt, impl_id: ast::def_id,
+fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
                     name: ast::ident) -> ast::def_id {
     if impl_id.crate == ast::local_crate {
         alt check ccx.tcx.items.get(impl_id.node) {
@@ -172,8 +120,8 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
         ret trans_static_callee(bcx, callee_id, base, mth_id,
                                 some((tys, sub_origins)));
       }
-      typeck::dict_iface(iid) {
-        ret trans_iface_callee(bcx, callee_id, base, iid, n_method);
+      typeck::dict_iface(iid, tps) {
+        ret trans_iface_callee(bcx, base, callee_id, n_method);
       }
       typeck::dict_param(n_param, n_bound) {
         fail "dict_param left in monomorphized function's dict substs";
@@ -181,20 +129,9 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
     }
 }
 
-
-// Method callee where the dict comes from a type param
-fn trans_param_callee(bcx: block, callee_id: ast::node_id,
-                      base: @ast::expr, iface_id: ast::def_id, n_method: uint,
-                      n_param: uint, n_bound: uint) -> lval_maybe_callee {
-    let {bcx, val} = trans_self_arg(bcx, base);
-    let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
-    trans_vtable_callee(bcx, dict_env(dict, val), dict,
-                        callee_id, iface_id, n_method)
-}
-
 // Method callee where the dict comes from a boxed iface
-fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
-                      base: @ast::expr, iface_id: ast::def_id, n_method: uint)
+fn trans_iface_callee(bcx: block, base: @ast::expr,
+                      callee_id: ast::node_id, n_method: uint)
     -> lval_maybe_callee {
     let {bcx, val} = trans_temp_expr(bcx, base);
     let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, val, [0, 0]),
@@ -202,8 +139,8 @@ fn trans_iface_callee(bcx: block, callee_id: ast::node_id,
     let box = Load(bcx, GEPi(bcx, val, [0, 1]));
     // FIXME[impl] I doubt this is alignment-safe
     let self = GEPi(bcx, box, [0, abi::box_field_body]);
-    trans_vtable_callee(bcx, dict_env(dict, self), dict,
-                        callee_id, iface_id, n_method)
+    trans_vtable_callee(bcx, self_env(self, expr_ty(bcx, base)), dict,
+                        callee_id, n_method)
 }
 
 fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
@@ -214,18 +151,6 @@ fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
     {inputs: args, output: out_ty}
 }
 
-fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
-                ptrs: [ValueRef]) {
-    let tbl = C_struct(ptrs);
-    let vt_gvar = str::as_c_str(name, {|buf|
-        llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
-    });
-    llvm::LLVMSetInitializer(vt_gvar, tbl);
-    llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
-    ccx.item_vals.insert(id, vt_gvar);
-    ccx.item_symbols.insert(id, name);
-}
-
 fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
     -> typeck::dict_origin {
     let dict_off = n_bound, i = 0u;
@@ -241,150 +166,93 @@ fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
     option::get(ps.dicts)[dict_off]
 }
 
-fn resolve_dicts_in_fn_ctxt(fcx: fn_ctxt, dicts: typeck::dict_res)
-    -> option<typeck::dict_res> {
-    let result = [];
-    for dict in *dicts {
-        result += [alt dict {
-          typeck::dict_static(iid, tys, sub) {
-            alt resolve_dicts_in_fn_ctxt(fcx, sub) {
-              some(sub) {
-                let tys = alt fcx.param_substs {
-                  some(substs) {
-                    vec::map(tys, {|t|
-                        ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
-                    })
-                  }
-                  _ { tys }
-                };
-                typeck::dict_static(iid, tys, sub)
-              }
-              none { ret none; }
-            }
+fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::dict_res)
+    -> typeck::dict_res {
+    @vec::map(*vts, {|d| resolve_vtable_in_fn_ctxt(fcx, d)})
+}
+
+fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::dict_origin)
+    -> typeck::dict_origin {
+    alt vt {
+      typeck::dict_static(iid, tys, sub) {
+        let tys = alt fcx.param_substs {
+          some(substs) {
+            vec::map(tys, {|t|
+                ty::substitute_type_params(fcx.ccx.tcx, substs.tys, t)
+            })
           }
-          typeck::dict_param(n_param, n_bound) {
-            alt fcx.param_substs {
-              some(substs) {
-                find_dict_in_fn_ctxt(substs, n_param, n_bound)
-              }
-              none { ret none; }
-            }
+          _ { tys }
+        };
+        typeck::dict_static(iid, tys, resolve_vtables_in_fn_ctxt(fcx, sub))
+      }
+      typeck::dict_param(n_param, n_bound) {
+        alt check fcx.param_substs {
+          some(substs) {
+            find_dict_in_fn_ctxt(substs, n_param, n_bound)
           }
-          _ { dict }
-        }];
+        }
+      }
+      _ { vt }
     }
-    some(@result)
 }
 
-fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
-                 fill: fn(ValueRef, block) -> block)
-    -> ValueRef {
-    let name = link::mangle_internal_name_by_path(ccx, pt);
-    let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
-    let fcx = new_fn_ctxt(ccx, [], llfn, none);
-    let bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
-    let bcx = fill(llfn, bcx);
-    build_return(bcx);
-    finish_fn(fcx, lltop);
-    ret llfn;
+fn vtable_id(origin: typeck::dict_origin) -> mono_id {
+    alt check origin {
+      typeck::dict_static(impl_id, substs, sub_dicts) {
+        @{def: impl_id, substs: substs,
+          dicts: if (*sub_dicts).len() == 0u { no_dicts }
+                 else { some_dicts(vec::map(*sub_dicts, vtable_id)) } }
+      }
+      typeck::dict_iface(iface_id, substs) {
+        @{def: iface_id, substs: substs, dicts: no_dicts}
+      }
+    }
 }
 
-fn trans_impl_wrapper(ccx: @crate_ctxt, pt: path,
-                      extra_tps: [ty::param_bounds], real_fn: ValueRef)
+fn get_vtable(ccx: @crate_ctxt, origin: typeck::dict_origin)
     -> ValueRef {
-    let {inputs: real_args, output: real_ret} =
-        llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
-    let extra_ptrs = [];
-    for tp in extra_tps {
-        extra_ptrs += [T_ptr(ccx.tydesc_type)];
-        for bound in *tp {
-            alt bound {
-              ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
-              _ {}
-            }
+    let hash_id = vtable_id(origin);
+    alt ccx.vtables.find(hash_id) {
+      some(val) { val }
+      none {
+        alt check origin {
+          typeck::dict_static(id, substs, sub_dicts) {
+            make_impl_vtable(ccx, id, substs, sub_dicts)
+          }
         }
+      }
     }
-    let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
-    let n_extra_ptrs = extra_ptrs.len();
-
-    let wrap_args = [T_ptr(T_dict())] +
-        vec::slice(real_args, 0u, first_tp_arg) +
-        vec::slice(real_args, first_tp_arg + n_extra_ptrs, real_args.len());
-    let llfn_ty = T_fn(wrap_args, real_ret);
-    trans_wrapper(ccx, pt, llfn_ty, {|llfn, bcx|
-        let dict = PointerCast(bcx, LLVMGetParam(llfn, 0 as c_uint), env_ty);
-        // retptr, self
-        let args = [LLVMGetParam(llfn, 1 as c_uint),
-                    LLVMGetParam(llfn, 2 as c_uint)];
-        let i = 0u;
-        // saved tydescs/dicts
-        while i < n_extra_ptrs {
-            i += 1u;
-            args += [load_inbounds(bcx, dict, [0, i as int])];
-        }
-        // the rest of the parameters
-        let j = 3u as c_uint;
-        let params_total = llvm::LLVMCountParamTypes(llfn_ty);
-        while j < params_total {
-            args += [LLVMGetParam(llfn, j)];
-            j += 1u as c_uint;
-        }
-        Call(bcx, real_fn, args);
-        bcx
-    })
 }
 
-fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
-                     iface_id: ast::def_id, ms: [@ast::method],
-                     tps: [ast::ty_param], it: @ast::item) {
-    if tps.len() > 0u { ret; }
-    let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
-                       path_name("wrap")];
-    let extra_tps = param_bounds(ccx, tps);
-    let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
-        alt vec::find(ms, {|m| m.ident == im.ident}) {
-          some(m) {
-            trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)],
-                               extra_tps, get_item_val(ccx, m.id))
-          }
-          _ {
-            ccx.sess.span_bug(it.span, "no matching method \
-                                        in trans_impl_vtable");
-          }
-        }
+fn make_vtable(ccx: @crate_ctxt, ptrs: [ValueRef]) -> ValueRef {
+    let tbl = C_struct(ptrs);
+    let vt_gvar = str::as_c_str(ccx.names("vtable"), {|buf|
+        llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
     });
-    let s = link::mangle_internal_name_by_path(
-        ccx, new_pt + [path_name("!vtable")]);
-    trans_vtable(ccx, it.id, s, ptrs);
+    llvm::LLVMSetInitializer(vt_gvar, tbl);
+    llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
+    lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
+    vt_gvar
 }
 
-fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
-                       n: uint) -> ValueRef {
-    let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
-                                         ty::mk_fn(ccx.tcx, m.fty), m.tps);
-    trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
-        let param = PointerCast(bcx, LLVMGetParam(llfn, 2u as c_uint),
-                                T_ptr(T_opaque_iface(ccx)));
-        let dict = Load(bcx, GEPi(bcx, param, [0, 0]));
-        let box = Load(bcx, GEPi(bcx, param, [0, 1]));
-        let self = GEPi(bcx, box, [0, abi::box_field_body]);
-        let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
-                                 T_ptr(T_array(T_ptr(llfty), n + 1u)));
-        let mptr = Load(bcx, GEPi(bcx, vtable, [0, n as int]));
-        let args = [PointerCast(bcx, dict, T_ptr(T_i8())),
-                    LLVMGetParam(llfn, 1u as c_uint),
-                    PointerCast(bcx, self, T_opaque_cbox_ptr(ccx))];
-        let i = 3u as c_uint, total = llvm::LLVMCountParamTypes(llfty);
-        while i < total {
-            args += [LLVMGetParam(llfn, i)];
-            i += 1u as c_uint;
+fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t],
+                    dicts: typeck::dict_res) -> ValueRef {
+    let tcx = ccx.tcx;
+    let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id)));
+    make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id), {|im|
+        let fty = ty::substitute_type_params(tcx, substs,
+                                             ty::mk_fn(tcx, im.fty));
+        if (*im.tps).len() > 0u || ty::type_has_vars(fty) {
+            C_null(type_of_fn_from_ty(ccx, fty, []))
+        } else {
+            let m_id = method_with_name(ccx, impl_id, im.ident);
+            option::get(monomorphic_fn(ccx, m_id, substs, some(dicts))).llfn
         }
-        Call(bcx, mptr, args);
-        bcx
-    })
+    }))
 }
 
-fn trans_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
+/*
+fn make_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
     let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
     let i_did = local_def(it.id), i = 0u;
     let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
@@ -528,6 +396,7 @@ fn get_dict_ptrs(bcx: block, origin: typeck::dict_origin)
       }
     }
 }
+}*/
 
 fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
     -> block {
@@ -541,8 +410,10 @@ fn trans_cast(bcx: block, val: @ast::expr, id: ast::node_id, dest: dest)
     let result = get_dest_addr(dest);
     Store(bcx, box, PointerCast(bcx, GEPi(bcx, result, [0, 1]),
                                 T_ptr(val_ty(box))));
-    let {bcx, val: dict} = get_dict(bcx, ccx.maps.dict_map.get(id)[0]);
-    Store(bcx, dict, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
-                                 T_ptr(val_ty(dict))));
+    let orig = ccx.maps.dict_map.get(id)[0];
+    let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
+    let vtable = get_vtable(bcx.ccx(), orig);
+    Store(bcx, vtable, PointerCast(bcx, GEPi(bcx, result, [0, 0]),
+                                   T_ptr(val_ty(vtable))));
     bcx
 }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 036b0177747..dc4ebe69d3a 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -92,6 +92,7 @@ export region, re_named, re_caller, re_block, re_inferred;
 export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
 export same_type;
 export ty_var_id;
+export ty_to_def_id;
 export ty_fn_args;
 export type_constr;
 export kind, kind_sendable, kind_copyable, kind_noncopyable;
@@ -2290,6 +2291,14 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
     }
 }
 
+fn ty_to_def_id(ty: t) -> ast::def_id {
+    alt check get(ty).struct {
+      ty_iface(id, _) | ty_class(id, _) | ty_res(id, _, _) | ty_enum(id, _) {
+        id
+      }
+    }
+}
+
 // Enum information
 type variant_info = @{args: [t], ctor_ty: t, name: str,
                       id: ast::def_id, disr_val: int};
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index caa0d3b73fe..9f1a2b73d9e 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -34,7 +34,7 @@ enum dict_origin {
     dict_static(ast::def_id, [ty::t], dict_res),
     // Param number, bound number
     dict_param(uint, uint),
-    dict_iface(ast::def_id),
+    dict_iface(ast::def_id, [ty::t]),
 }
 type dict_map = hashmap<ast::node_id, dict_res>;
 
@@ -3361,8 +3361,8 @@ mod dict {
                 }
             }
           }
-          ty::ty_iface(did, _) if iface_id == did {
-            ret dict_iface(did);
+          ty::ty_iface(did, tps) if iface_id == did {
+            ret dict_iface(did, tps);
           }
           _ {
             let found = none;