Change:
Spidermonkey's type is a union of size 64 bits. We represent this as in Rust. This works great on 64bit platforms. On 32bit platforms, the values get mangled when passed to the C library functions. This seems to be an ABI issue. We've encountered this before with which was about 32bit ARM. This gist contains sample programs and the generated IR for minimal test programs using rust-mozjs: Note that you will need my 32bit branch of rust-mozjs: You can put debugging printfs in in to see the value on the C side. The only notable thing I see in the IR is that the clang IR has when passing the . This seems like a Rust bug, but I'd also be interested if there is a workaround that will work on all platforms.
cc
cc me

Discussion:
did) } Some(..) | None => { <del> let c = foreign::llvm_calling_convention(ccx, fn_ty.abi); let cconv = c.unwrap_or(lib::llvm::CCallConv); let llty = type_of_fn_from_ty(ccx, t); get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod, name.as_slice(), cconv, llty, fn_ty.sig.output) </del> <ins> foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, name.as_slice(), None) </ins> } } }

match ni.node { ast::ForeignItemFn(..) => { let abi = ccx.tcx.map.get_foreign_abi(id); <del> foreign::register_foreign_item_fn(ccx, abi, ni) </del> <ins> let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(ni); foreign::register_foreign_item_fn(ccx, abi, ty, name.get().as_slice(), Some(ni.span)) </ins> } ast::ForeignItemStatic(..) => { foreign::register_static(ccx, ni)

} } <del> pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, foreign_item: &ast::ForeignItem) -> ValueRef { </del> <ins> pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t, name: &str, span: Option<Span>) -> ValueRef { </ins> /*! * Registers a foreign function found in a library. * Just adds a LLVM global. */ debug!("register_foreign_item_fn(abi={},  <del> path={},  foreign_item.id={})", </del> <ins> ty={},  name={})", </ins> abi.repr(ccx.tcx()), <del> ccx.tcx.map.path_to_str(foreign_item.id), foreign_item.id); </del> <ins> fty.repr(ccx.tcx()), name); </ins> let cc = match llvm_calling_convention(ccx, abi) { Some(cc) => cc, None => { <del> ccx.sess().span_fatal(foreign_item.span, format!("ABI `{}` has no suitable calling convention  for target architecture", abi.user_string(ccx.tcx()))); </del> <ins> match span { Some(s) => { ccx.sess().span_fatal(s, format!("ABI `{}` has no suitable calling convention  for target architecture", abi.user_string(ccx.tcx()))) } None => { ccx.sess().fatal( format!("ABI `{}` has no suitable calling convention  for target architecture", abi.user_string(ccx.tcx()))) } } </ins> } }; // Register the function as a C extern fn <del> let lname = link_name(foreign_item); let tys = foreign_types_for_id(ccx, foreign_item.id); </del> <ins> let tys = foreign_types_for_fn_ty(ccx, fty); </ins> // Make sure the calling convention is right for variadic functions // (should've been caught if not in typeck)

let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod, <del> lname.get(), </del> <ins> name, </ins> cc, llfn_ty, tys.fn_sig.output);

pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { let _icx = push_ctxt("foreign::trans_foreign_mod"); for &foreign_item in foreign_mod.items.iter() { <ins> let lname = link_name(foreign_item); </ins> match foreign_item.node { ast::ForeignItemFn(..) => { match foreign_mod.abi { Rust | RustIntrinsic => {} <del> abi => { register_foreign_item_fn(ccx, abi, foreign_item); } </del> <ins> abi => { let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id); register_foreign_item_fn(ccx, abi, ty, lname.get().as_slice(), Some(foreign_item.span)); } </ins> } } _ => {} } <del> let lname = link_name(foreign_item); </del> ccx.item_symbols.borrow_mut().insert(foreign_item.id, lname.get().to_strbuf()); }

<ins> -include ../tools.mk all: $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o $(RUSTC) testcrate.rs -L $(TMPDIR) $(RUSTC) test.rs -L $(TMPDIR) $(call RUN,test) || exit 1 </ins>

<ins> #include <stdio.h> #include <stdint.h> typedef union TestUnion { uint64_t bits; } TestUnion; uint64_t give_back(TestUnion tu) { return tu.bits; } </ins>

<ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate testcrate; use std::mem; #[link(name = "test", kind = "static")] extern { fn give_back(tu: testcrate::TestUnion) -> u64; } fn main() { let magic: u64 = 0xDEADBEEF; // Let's test calling it cross crate let back = unsafe { testcrate::give_back(mem::transmute(magic)) }; assert_eq!(magic, back); // And just within this crate let back = unsafe { give_back(mem::transmute(magic)) }; assert_eq!(magic, back); } </ins>

<ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![crate_type = "lib"] pub struct TestUnion { val: u64 } #[link(name = "test", kind = "static")] extern { pub fn give_back(tu: TestUnion) -> u64; } </ins>