about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLindsey Kuper <lkuper@mozilla.com>2011-07-27 18:55:15 -0700
committerLindsey Kuper <lkuper@mozilla.com>2011-07-27 19:43:21 -0700
commit7073ee4e31d32cfdc1401cfefaa2e3ed07b43f48 (patch)
treede98c87b5648c3956b88827e76608112ec559104 /src
parent54c1c07ab1a9ba311bde3a1f80687a7e64c7edae (diff)
downloadrust-7073ee4e31d32cfdc1401cfefaa2e3ed07b43f48.tar.gz
rust-7073ee4e31d32cfdc1401cfefaa2e3ed07b43f48.zip
Some work on backwarding for issue #702.
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans.rs120
1 files changed, 100 insertions, 20 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2e3c2a41446..0b0b31b2064 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -6534,6 +6534,7 @@ fn trans_fn(cx: @local_ctxt, sp: &span, f: &ast::_fn, llfndecl: ValueRef,
 // helper function for create_vtbl.
 fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
                        ty_params: &ast::ty_param[], with_obj_ty: ty::t,
+                       backwarding_vtbl: option::t[ValueRef],
                        additional_field_tys: &ty::t[]) -> ValueRef {
 
 
@@ -6552,9 +6553,14 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
     let mcx: @local_ctxt = @{path: cx.path + ~["method", m.ident] with *cx};
 
     // Make up a name for the forwarding function.
-    let s: str =
-        mangle_internal_name_by_path_and_seq(mcx.ccx, mcx.path,
-                                             "forwarding_fn");
+    let fn_name: str;
+    alt (backwarding_vtbl) {
+        none. { fn_name = "forwarding_fn"; }
+        some(_) { fn_name = "backwarding_fn"; }
+    }
+
+    let s: str = mangle_internal_name_by_path_and_seq(mcx.ccx, mcx.path,
+                                                      fn_name);
 
     // Get the forwarding function's type and declare it.
     let llforwarding_fn_ty: TypeRef =
@@ -6574,6 +6580,21 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
     let llself_obj_ptr = alloca(bcx, fcx.lcx.ccx.rust_object_type);
     bcx.build.Store(fcx.llenv, llself_obj_ptr);
 
+    // Do backwarding if necessary.
+    alt (backwarding_vtbl) {
+        none. { /* fall through */ }
+        some(bv) {
+            // Grab the vtable out of the self-object.
+            let llself_obj_vtbl =
+                bcx.build.GEP(llself_obj_ptr, ~[C_int(0),
+                                                C_int(abi::obj_field_vtbl)]);
+
+            // And replace it with the backwarding vtbl.
+            let llbv = bcx.build.PointerCast(bv, T_ptr(T_empty_struct()));
+            bcx.build.Store(llbv, llself_obj_vtbl);
+        }
+    }
+
     // Grab hold of the outer object so we can pass it into the inner object,
     // in case that inner object needs to make any self-calls.  (Such calls
     // will need to dispatch back through the outer object.)
@@ -6733,22 +6754,21 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
     ret llfn;
 }
 
+// Used only inside create_vtbl and create_backwarding_vtbl to distinguish
+// different kinds of slots we'll have to create.
+tag vtbl_mthd {
+    // Normal methods are complete AST nodes, but for forwarding methods,
+    // the only information we'll have about them is their type.
+    normal_mthd(@ast::method);
+    fwding_mthd(@ty::method);
+}
+
 // Create a vtable for an object being translated.  Returns a pointer into
 // read-only memory.
 fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
                ty_params: &ast::ty_param[], with_obj_ty: option::t[ty::t],
                additional_field_tys: &ty::t[]) -> ValueRef {
 
-    // Used only inside create_vtbl to distinguish different kinds of slots
-    // we'll have to create.
-    tag vtbl_mthd {
-
-        // Normal methods are complete AST nodes, but for forwarding methods,
-        // the only information we'll have about them is their type.
-        normal_mthd(@ast::method);
-        fwding_mthd(@ty::method);
-    }
-
     let dtor = C_null(T_ptr(T_i8()));
     alt ob.dtor {
       some(d) {
@@ -6760,6 +6780,7 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
 
     let llmethods: ValueRef[] = ~[dtor];
     let meths: vtbl_mthd[] = ~[];
+    let backwarding_vtbl: option::t[ValueRef] = none;
 
     alt with_obj_ty {
       none. {
@@ -6794,8 +6815,8 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
           }
           _ {
             // Shouldn't happen.
-            cx.ccx.sess.bug("create_vtbl(): trying to extend a " +
-                                "non-object");
+            cx.ccx.sess.bug("create_vtbl(): trying to extend a \
+                            non-object");
           }
         }
 
@@ -6805,7 +6826,6 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
                         addtl_meths: (@ast::method)[]) ->
            option::t[vtbl_mthd] {
 
-
             alt m {
               fwding_mthd(fm) {
                 // Since fm is a fwding_mthd, and we're checking to
@@ -6863,7 +6883,7 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
                                                   meths);
 
     // Now that we have our list of methods, we can process them in order.
-    for m: vtbl_mthd  in meths {
+    for m: vtbl_mthd in meths {
         alt m {
           normal_mthd(nm) {
             llmethods += ~[process_normal_mthd(cx, nm, self_ty, ty_params)];
@@ -6877,13 +6897,14 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, self_ty: ty::t, ob: &ast::_obj,
                 // This shouldn't happen; if we're trying to process a
                 // forwarding method, then we should always have a
                 // with_obj_ty.
-                cx.ccx.sess.bug("create_vtbl(): trying to create " +
-                                    "forwarding method without a type " +
-                                    "of object to forward to");
+                cx.ccx.sess.bug("create_vtbl(): trying to create \
+                                forwarding method without a type \
+                                of object to forward to");
               }
               some(t) {
                 llmethods +=
                     ~[process_fwding_mthd(cx, sp, fm, ty_params, t,
+                                          backwarding_vtbl,
                                           additional_field_tys)];
               }
             }
@@ -6914,6 +6935,65 @@ fn trans_dtor(cx: @local_ctxt, self_ty: ty::t, ty_params: &ast::ty_param[],
     ret llfn;
 }
 
+fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, with_obj_ty: ty::t,
+                           outer_obj_ty: ty::t) -> ValueRef {
+
+    // This vtbl needs to have slots for all of the methods on an inner
+    // object, and it needs to forward them to the corresponding slots on the
+    // outer object.  All we know about either one are their types.
+
+    let dtor = C_null(T_ptr(T_i8()));
+    let llmethods: ValueRef[] = ~[dtor];
+    let meths: vtbl_mthd[]= ~[];
+
+    // Gather up methods on the inner object.
+    alt ty::struct(cx.ccx.tcx, with_obj_ty) {
+        ty::ty_obj(with_obj_methods) {
+            for m: ty::method in with_obj_methods {
+                meths += ~[fwding_mthd(@m)];
+            }
+        }
+        _ {
+            // Shouldn't happen.
+            cx.ccx.sess.bug("create_backwarding_vtbl(): trying to extend a \
+                            non-object");
+        }
+    }
+
+    // Methods should have already been sorted, so no need to do so again.
+
+    for m: vtbl_mthd in meths {
+        alt m {
+            normal_mthd(nm) {
+                cx.ccx.sess.bug("backwarding vtables shouldn't contain \
+                                 normal methods");
+            }
+            fwding_mthd(fm) {
+                // We pass outer_obj_ty to process_fwding_mthd() because it's
+                // the one being forwarded to.
+                llmethods += ~[process_fwding_mthd(
+                        cx, sp, fm, ~[], outer_obj_ty,
+                        none,
+                        ~[])];
+            }
+        }
+    }
+
+    let vtbl = C_struct(llmethods);
+    let vtbl_name =
+        mangle_internal_name_by_path(cx.ccx,
+                                     cx.path + ~["backwarding_vtbl"]);
+    let gvar =
+        llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name));
+    llvm::LLVMSetInitializer(gvar, vtbl);
+    llvm::LLVMSetGlobalConstant(gvar, True);
+    llvm::LLVMSetLinkage(gvar,
+                         lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+
+    ret gvar;
+
+}
+
 // trans_obj: creates an LLVM function that is the object constructor for the
 // object being translated.
 fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,