]> git.lizzy.rs Git - rust.git/commitdiff
trans: Pass fat pointers as two arguments even for FFI.
authorEduard Burtescu <edy.burt@gmail.com>
Wed, 24 Feb 2016 09:09:25 +0000 (11:09 +0200)
committerEduard Burtescu <edy.burt@gmail.com>
Thu, 17 Mar 2016 19:51:50 +0000 (21:51 +0200)
src/librustc_trans/trans/abi.rs
src/librustc_trans/trans/foreign.rs

index 9aabceb6b0ee5785b04521adcaff1c0a5653450f..a73f5ff90d96b908e5ce3434f21412287a1efb94 100644 (file)
@@ -12,7 +12,7 @@
 
 use llvm::{self, AttrHelper, ValueRef};
 use trans::attributes;
-use trans::common::return_type_is_void;
+use trans::common::{return_type_is_void, type_is_fat_ptr};
 use trans::context::CrateContext;
 use trans::cabi_x86;
 use trans::cabi_x86_64;
@@ -184,10 +184,20 @@ pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             _ => Type::void(ccx)
         };
 
+        let mut args = Vec::with_capacity(sig.inputs.len() + extra_args.len());
+        for ty in sig.inputs.iter().chain(extra_args.iter()) {
+            let llty = c_type_of(ccx, ty);
+            if type_is_fat_ptr(ccx.tcx(), ty) {
+                args.extend(llty.field_types().into_iter().map(|llty| {
+                    ArgType::direct(llty, None, None, None)
+                }));
+            } else {
+                args.push(ArgType::direct(llty, None, None, None));
+            }
+        }
+
         let mut fty = FnType {
-            args: sig.inputs.iter().chain(extra_args.iter()).map(|&ty| {
-                ArgType::direct(c_type_of(ccx, ty), None, None, None)
-            }).collect(),
+            args: args,
             ret: ArgType::direct(rty, None, None, None),
             variadic: sig.variadic,
             cconv: cconv
index 0cf30aca94cd27a797633432c67712181af91a43..46eb8006272a5c0ab92f7c9708186622bb846837 100644 (file)
@@ -13,7 +13,7 @@
 use llvm::{ValueRef, get_param};
 use llvm;
 use middle::weak_lang_items;
-use trans::abi::{self, Abi, FnType};
+use trans::abi::{Abi, FnType};
 use trans::attributes;
 use trans::base::{llvm_linkage_by_name, push_ctxt};
 use trans::base;
 use trans::common::*;
 use trans::debuginfo::DebugLoc;
 use trans::declare;
-use trans::expr;
 use trans::machine;
 use trans::monomorphize;
 use trans::type_::Type;
-use trans::type_of::*;
 use trans::type_of;
 use trans::value::Value;
 use middle::infer;
@@ -167,17 +165,40 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
     }
 
-    let mut offset = 0;
-    for (i, arg_ty) in fn_type.args.iter().enumerate() {
-        let mut llarg_rust = llargs_rust[i + offset];
+    let mut i = 0;
+    for &passed_arg_ty in &passed_arg_tys {
+        let arg_ty = fn_type.args[i];
 
         if arg_ty.is_ignore() {
+            i += 1;
+            continue;
+        }
+
+        if type_is_fat_ptr(ccx.tcx(), passed_arg_ty) {
+            // Fat pointers are one pointer and one integer or pointer.
+            let (a, b) = (fn_type.args[i], fn_type.args[i + 1]);
+            assert_eq!((a.cast, b.cast), (None, None));
+            assert!(!a.is_indirect() && !b.is_indirect());
+
+            if let Some(ty) = a.pad {
+                llargs_foreign.push(C_undef(ty));
+            }
+            llargs_foreign.push(llargs_rust[i]);
+            i += 1;
+
+            if let Some(ty) = b.pad {
+                llargs_foreign.push(C_undef(ty));
+            }
+            llargs_foreign.push(llargs_rust[i]);
+            i += 1;
             continue;
         }
 
         // Does Rust pass this argument by pointer?
-        let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
+        let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_ty);
 
+        let mut llarg_rust = llargs_rust[i];
+        i += 1;
         debug!("argument {}, llarg_rust={:?}, rust_indirect={}, arg_ty={:?}",
                i,
                Value(llarg_rust),
@@ -187,14 +208,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // Ensure that we always have the Rust value indirectly,
         // because it makes bitcasting easier.
         if !rust_indirect {
-            let scratch = base::alloc_ty(bcx, passed_arg_tys[i], "__arg");
-            if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
-                Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
-                Store(bcx, llargs_rust[i + offset + 1], expr::get_meta(bcx, scratch));
-                offset += 1;
-            } else {
-                base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
-            }
+            let scratch = base::alloc_ty(bcx, passed_arg_ty, "__arg");
+            base::store_ty(bcx, llarg_rust, scratch, passed_arg_ty);
             llarg_rust = scratch;
         }
 
@@ -202,9 +217,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                Value(llarg_rust));
 
         // Check whether we need to do any casting
-        match arg_ty.cast {
-            Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
-            None => ()
+        if let Some(ty) = arg_ty.cast {
+            llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to());
         }
 
         debug!("llarg_rust={:?} (after casting)",
@@ -214,22 +228,19 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let foreign_indirect = arg_ty.is_indirect();
         let llarg_foreign = if foreign_indirect {
             llarg_rust
+        } else if passed_arg_ty.is_bool() {
+            let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
+            Trunc(bcx, val, Type::i1(bcx.ccx()))
         } else {
-            if passed_arg_tys[i].is_bool() {
-                let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
-                Trunc(bcx, val, Type::i1(bcx.ccx()))
-            } else {
-                Load(bcx, llarg_rust)
-            }
+            Load(bcx, llarg_rust)
         };
 
         debug!("argument {}, llarg_foreign={:?}",
                i, Value(llarg_foreign));
 
         // fill padding with undef value
-        match arg_ty.pad {
-            Some(ty) => llargs_foreign.push(C_undef(ty)),
-            None => ()
+        if let Some(ty) = arg_ty.pad {
+            llargs_foreign.push(C_undef(ty));
         }
         llargs_foreign.push(llarg_foreign);
     }
@@ -552,16 +563,16 @@ unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // Build up the arguments to the call to the rust function.
         // Careful to adapt for cases where the native convention uses
         // a pointer and Rust does not or vice versa.
+        let mut tys = fn_ty.args.iter().zip(rust_param_tys);
         for i in 0..fn_sig.inputs.len() {
             let rust_ty = fn_sig.inputs[i];
             let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
-            let llty = rust_param_tys.next().expect("Not enough parameter types!");
+            let (llforeign_arg_ty, llty) = tys.next().expect("Not enough parameter types!");
             let llrust_ty = if rust_indirect {
                 llty.element_type()
             } else {
                 llty
             };
-            let llforeign_arg_ty = fn_ty.args[i];
             let foreign_indirect = llforeign_arg_ty.is_indirect();
 
             if llforeign_arg_ty.is_ignore() {
@@ -574,6 +585,19 @@ unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
             let mut llforeign_arg = get_param(llwrapfn, foreign_index);
 
+            if type_is_fat_ptr(ccx.tcx(), rust_ty) {
+                // Fat pointers are one pointer and one integer or pointer.
+                let a = llforeign_arg_ty;
+                let (b, _) = tys.next().expect("Not enough parameter types!");
+                assert_eq!((a.cast, b.cast), (None, None));
+                assert!(!a.is_indirect() && !b.is_indirect());
+
+                llrust_args.push(llforeign_arg);
+                let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
+                llrust_args.push(get_param(llwrapfn, foreign_index));
+                continue;
+            }
+
             debug!("llforeign_arg {}{}: {:?}", "#",
                    i, Value(llforeign_arg));
             debug!("rust_indirect = {}, foreign_indirect = {}",
@@ -624,15 +648,7 @@ unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
             debug!("llrust_arg {}{}: {:?}", "#",
                    i, Value(llrust_arg));
-            if type_is_fat_ptr(ccx.tcx(), rust_ty) {
-                let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
-                llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
-                                llrust_arg, abi::FAT_PTR_ADDR), llrust_ty.ptr_to())));
-                llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
-                                llrust_arg, abi::FAT_PTR_EXTRA), next_llrust_ty.ptr_to())));
-            } else {
-                llrust_args.push(llrust_arg);
-            }
+            llrust_args.push(llrust_arg);
         }
 
         // Perform the call itself