@@ -5366,7 +5366,7 @@ fn c_stack_tys(ccx: @crate_ctxt,
5366
5366
ty:: ty_native_fn ( _, arg_tys, ret_ty) {
5367
5367
let llargtys = type_of_explicit_args ( ccx, sp, arg_tys) ;
5368
5368
check non_ty_var( ccx, ret_ty) ; // NDM does this truly hold?
5369
- let llretty = type_of_inner ( ccx, sp, ret_ty) ;
5369
+ let llretty = T_ptr ( type_of_inner ( ccx, sp, ret_ty) ) ;
5370
5370
let bundle_ty = T_struct ( llargtys + [ llretty] ) ;
5371
5371
ret @{
5372
5372
arg_tys : llargtys,
@@ -5385,31 +5385,58 @@ fn c_stack_tys(ccx: @crate_ctxt,
5385
5385
}
5386
5386
}
5387
5387
5388
- // For c-stack ABIs, we must generate shim functions for making
5389
- // the call. These shim functions will unpack arguments out of
5390
- // a struct and then invoke the base function.
5388
+ // For each native function F, we generate a wrapper function W and a shim
5389
+ // function S that all work together. The wrapper function W is the function
5390
+ // that other rust code actually invokes. Its job is to marshall the
5391
+ // arguments into a struct. It then uses a small bit of assembly to switch
5392
+ // over to the C stack and invoke the shim function. The shim function S then
5393
+ // unpacks the arguments from the struct and invokes the actual function F
5394
+ // according to its specified calling convention.
5391
5395
//
5392
5396
// Example: Given a native c-stack function F(x: X, y: Y) -> Z,
5393
- // we generate a shim function S that is something like:
5397
+ // we generate a wrapper function W that looks like:
5394
5398
//
5395
- // void S(struct F_Args { X x; Y y; Z *z; } *args) {
5399
+ // void W(Z* dest, void *env, X x, Y y) {
5400
+ // struct { X x; Y y; Z *z; } args = { x, y, z };
5401
+ // call_on_c_stack_shim(S, &args);
5402
+ // }
5403
+ //
5404
+ // The shim function S then looks something like:
5405
+ //
5406
+ // void S(struct { X x; Y y; Z *z; } *args) {
5396
5407
// *args->z = F(args->x, args->y);
5397
5408
// }
5398
5409
//
5410
+ // However, if the return type of F is dynamically sized or of aggregate type,
5411
+ // the shim function looks like:
5412
+ //
5413
+ // void S(struct { X x; Y y; Z *z; } *args) {
5414
+ // F(args->z, args->x, args->y);
5415
+ // }
5416
+ //
5417
+ // Note: on i386, the layout of the args struct is generally the same as the
5418
+ // desired layout of the arguments on the C stack. Therefore, we could use
5419
+ // upcall_alloc_c_stack() to allocate the `args` structure and switch the
5420
+ // stack pointer appropriately to avoid a round of copies. (In fact, the shim
5421
+ // function itself is unnecessary). We used to do this, in fact, and will
5422
+ // perhaps do so in the future.
5399
5423
fn trans_native_mod ( lcx : @local_ctxt , native_mod : ast:: native_mod ) {
5400
5424
fn build_shim_fn ( lcx : @local_ctxt ,
5401
5425
native_item : @ast:: native_item ,
5402
- llshimfn : ValueRef ,
5403
- cc : uint ) {
5426
+ tys : @ c_stack_tys ,
5427
+ cc : uint ) -> ValueRef {
5404
5428
let lname = link_name ( native_item) ;
5405
5429
let ccx = lcx_ccx ( lcx) ;
5406
5430
let span = native_item. span ;
5407
- let id = native_item. id ;
5408
- let tys = c_stack_tys ( ccx, span, id) ;
5409
5431
5410
5432
// Declare the "prototype" for the base function F:
5411
5433
let llbasefn = decl_fn ( ccx. llmod , lname, cc, tys. base_fn_ty ) ;
5412
5434
5435
+ // Create the shim function:
5436
+ let shim_name = lname + "__c_stack_shim" ;
5437
+ let llshimfn = decl_internal_cdecl_fn (
5438
+ ccx. llmod , shim_name, tys. shim_fn_ty ) ;
5439
+
5413
5440
// Declare the body of the shim function:
5414
5441
let fcx = new_fn_ctxt ( lcx, span, llshimfn) ;
5415
5442
let bcx = new_top_block_ctxt ( fcx) ;
@@ -5423,11 +5450,39 @@ fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod) {
5423
5450
i += 1 u;
5424
5451
}
5425
5452
5426
- // Create the call itself:
5453
+ // Create the call itself and store the return value :
5427
5454
let llretval = CallWithConv ( bcx, llbasefn, llargvals, cc) ;
5428
- store_inbounds ( bcx, llretval, llargbundle, [ 0 , n as int ] ) ;
5455
+ store_inbounds ( bcx, llretval, llargbundle, [ 0 , n as int , 0 ] ) ;
5456
+
5457
+ // Finish up:
5458
+ build_return ( bcx) ;
5459
+ finish_fn ( fcx, lltop) ;
5460
+
5461
+ ret llshimfn;
5462
+ }
5463
+
5464
+ fn build_wrap_fn ( lcx : @local_ctxt ,
5465
+ native_item : @ast:: native_item ,
5466
+ tys : @c_stack_tys ,
5467
+ llshimfn : ValueRef ,
5468
+ llwrapfn : ValueRef ) {
5469
+ let fcx = new_fn_ctxt ( lcx, span, llshimfn) ;
5470
+ let bcx = new_top_block_ctxt ( fcx) ;
5471
+ let lltop = bcx. llbb ;
5472
+
5473
+ // Allocate the struct and write the arguments into it.
5474
+ let llargbundle = alloca ( bcx, tys. bundle_ty ) ;
5475
+ let imp = 2 u, i = 0 u, n = vec:: len ( tys. arg_tys ) ;
5476
+ while i < n {
5477
+ let llargval = llvm:: LLVMGetParam ( llwrapfn, i + imp) ;
5478
+ store_inbounds ( bcx, llargval, llargbundle, [ 0 , i as int ] ) ;
5479
+ i += 1 u;
5480
+ }
5481
+ let llretptr = llvm:: LLVMGetParam ( llwrapfn, 0 ) ;
5482
+ store_inbounds ( bcx, llretptr, llargbundle, [ 0 , n as int ] ) ;
5483
+
5484
+ // Create call itself:
5429
5485
5430
- // Finish up.
5431
5486
build_return ( bcx) ;
5432
5487
finish_fn ( fcx, lltop) ;
5433
5488
}
@@ -5445,9 +5500,11 @@ fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod) {
5445
5500
ast:: native_item_ty. { }
5446
5501
ast:: native_item_fn ( fn_decl, _) {
5447
5502
let id = native_item. id ;
5503
+ let tys = c_stack_tys ( ccx, span, id) ;
5448
5504
alt ccx. item_ids . find ( id) {
5449
- some ( llshimfn) {
5450
- build_shim_fn ( lcx, native_item, llshimfn, cc) ;
5505
+ some ( llwrapfn) {
5506
+ let llshimfn = build_shim_fn ( lcx, native_item, cc, tys) ;
5507
+ build_wrap_fn ( lcx, native_item, tys, llshimfn, llwrapfn) ;
5451
5508
}
5452
5509
5453
5510
none. {
@@ -5548,14 +5605,6 @@ fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
5548
5605
let path = path;
5549
5606
let llfty =
5550
5607
type_of_fn_from_ty ( ccx, sp, node_type, std:: vec:: len ( ty_params) ) ;
5551
- alt ty:: struct ( ccx. tcx , node_type) {
5552
- ty:: ty_fn ( _, inputs, output, rs, _) {
5553
- check non_ty_var ( ccx, output) ;
5554
- llfty = type_of_fn ( ccx, sp, false , ast_util:: ret_by_ref ( rs) , inputs,
5555
- output, vec:: len ( ty_params) ) ;
5556
- }
5557
- _ { ccx. sess . bug ( "register_fn(): fn item doesn't have fn type!" ) ; }
5558
- }
5559
5608
let ps: str = mangle_exported_name ( ccx, path, node_type) ;
5560
5609
let llfn: ValueRef = decl_cdecl_fn ( ccx. llmod , ps, llfty) ;
5561
5610
ccx. item_ids . insert ( node_id, llfn) ;
@@ -5715,33 +5764,6 @@ fn raw_native_fn_type(ccx: @crate_ctxt, sp: span, args: [ty::arg],
5715
5764
ret T_fn ( type_of_explicit_args ( ccx, sp, args) , type_of ( ccx, sp, ret_ty) ) ;
5716
5765
}
5717
5766
5718
- fn register_native_fn ( ccx : @crate_ctxt , sp : span , _path : [ str ] , name : str ,
5719
- id : ast:: node_id ) {
5720
- let fn_type = node_id_type ( ccx, id) ; // NB: has no type params
5721
- let abi = ty:: ty_fn_abi ( ccx. tcx , fn_type) ;
5722
-
5723
- alt abi {
5724
- ast : : native_abi_rust_intrinsic. {
5725
- let num_ty_param = native_fn_ty_param_count ( ccx, id) ;
5726
- let fn_type = native_fn_wrapper_type ( ccx, sp, num_ty_param, fn_type) ;
5727
- let ri_name = "rust_intrinsic_" + name;
5728
- let llnativefn = get_extern_fn ( ccx. externs , ccx. llmod , ri_name,
5729
- lib:: llvm:: LLVMCCallConv , fn_type) ;
5730
- ccx. item_ids . insert ( id, llnativefn) ;
5731
- ccx. item_symbols . insert ( id, ri_name) ;
5732
- }
5733
-
5734
- ast:: native_abi_cdecl. | ast:: native_abi_stdcall. {
5735
- let tys = c_stack_tys ( ccx, sp, id) ;
5736
- let shim_name = name + "__c_stack_shim" ;
5737
- let llshimfn = decl_internal_cdecl_fn (
5738
- ccx. llmod , shim_name, tys. shim_fn_ty ) ;
5739
- ccx. item_ids . insert ( id, llshimfn) ;
5740
- ccx. item_symbols . insert ( id, shim_name) ;
5741
- }
5742
- }
5743
- }
5744
-
5745
5767
fn item_path ( item : @ast:: item ) -> [ str ] { ret [ item. ident ] ; }
5746
5768
5747
5769
fn link_name ( i : @ast:: native_item ) -> str {
@@ -5751,14 +5773,36 @@ fn link_name(i: @ast::native_item) -> str {
5751
5773
}
5752
5774
}
5753
5775
5754
-
5755
5776
fn collect_native_item ( ccx : @crate_ctxt , i : @ast:: native_item , & & pt: [ str ] ,
5756
5777
_v : vt < [ str ] > ) {
5757
5778
alt i. node {
5758
- ast:: native_item_fn ( _, _ ) {
5779
+ ast:: native_item_fn ( _, tps ) {
5759
5780
if !ccx. obj_methods . contains_key ( i. id ) {
5760
- let name = link_name ( i) ;
5761
- register_native_fn ( ccx, i. span , pt, name, i. id ) ;
5781
+ // FIXME NDM abi should come from attr
5782
+ let abi = ty:: ty_fn_abi ( ccx. tcx , fn_type) ;
5783
+
5784
+ alt abi {
5785
+ ast : : native_abi_rust_intrinsic. {
5786
+ // For intrinsics: link the function directly to the intrinsic
5787
+ // function itself.
5788
+ let num_ty_param = vec:: len ( tps) ;
5789
+ let node_type = node_id_type ( ccx, id) ;
5790
+ let fn_type = type_of_fn_from_ty ( ccx, sp, node_type, num_ty_param) ;
5791
+ let ri_name = "rust_intrinsic_" + name;
5792
+ let llnativefn = get_extern_fn ( ccx. externs , ccx. llmod , ri_name,
5793
+ lib:: llvm:: LLVMCCallConv , fn_type) ;
5794
+ ccx. item_ids . insert ( id, llnativefn) ;
5795
+ ccx. item_symbols . insert ( id, ri_name) ;
5796
+ }
5797
+
5798
+ ast:: native_abi_cdecl. | ast:: native_abi_stdcall. {
5799
+ // For true external functions: create a rust wrapper
5800
+ // and link to that. The rust wrapper will handle
5801
+ // switching to the C stack.
5802
+ let new_pt = pt + [ i. ident ] ;
5803
+ register_fn ( ccx, i. span , new_pt, "native fn" , tps, i. id ) ;
5804
+ }
5805
+ }
5762
5806
}
5763
5807
}
5764
5808
_ { }
0 commit comments