@@ -68,18 +68,23 @@ fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
68
68
{ env: obj_env ( val) with lval_static_fn ( bcx, did, e. id ) }
69
69
}
70
70
71
+ fn wrapper_fn_ty ( ccx : @crate_ctxt , dict_ty : TypeRef , m : ty:: method )
72
+ -> { ty: ty:: t, llty: TypeRef } {
73
+ let fty = ty:: mk_fn ( ccx. tcx , m. fty ) ;
74
+ let bare_fn_ty = type_of_fn_from_ty ( ccx, ast_util:: dummy_sp ( ) ,
75
+ fty, * m. tps ) ;
76
+ let { inputs, output} = llfn_arg_tys ( bare_fn_ty) ;
77
+ { ty: fty, llty: T_fn ( [ dict_ty] + inputs, output) }
78
+ }
79
+
71
80
fn trans_vtable_callee ( bcx : @block_ctxt , self : ValueRef , dict : ValueRef ,
72
81
fld_expr : @ast:: expr , iface_id : ast:: def_id ,
73
82
n_method : uint ) -> lval_maybe_callee {
74
83
let bcx = bcx, ccx = bcx_ccx ( bcx) , tcx = ccx. tcx ;
75
84
let method = ty:: iface_methods ( tcx, iface_id) [ n_method] ;
76
- let fty = ty:: mk_fn ( tcx, method. fty ) ;
77
- let bare_fn_ty = type_of_fn_from_ty ( ccx, ast_util:: dummy_sp ( ) ,
78
- fty, * method. tps ) ;
79
- let { inputs: bare_inputs , output} = llfn_arg_tys ( bare_fn_ty) ;
80
- let fn_ty = T_fn ( [ val_ty ( dict) ] + bare_inputs, output) ;
85
+ let { ty: fty, llty: llfty} = wrapper_fn_ty ( ccx, val_ty ( dict) , method) ;
81
86
let vtable = PointerCast ( bcx, Load ( bcx, GEPi ( bcx, dict, [ 0 , 0 ] ) ) ,
82
- T_ptr ( T_array ( T_ptr ( fn_ty ) , n_method + 1 u) ) ) ;
87
+ T_ptr ( T_array ( T_ptr ( llfty ) , n_method + 1 u) ) ) ;
83
88
let mptr = Load ( bcx, GEPi ( bcx, vtable, [ 0 , n_method as int ] ) ) ;
84
89
let generic = none;
85
90
if vec:: len ( * method. tps ) > 0 u || ty:: type_contains_params ( tcx, fty) {
@@ -138,9 +143,36 @@ fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
138
143
{ inputs: args, output: out_ty}
139
144
}
140
145
141
- fn trans_wrapper ( ccx : @crate_ctxt , pt : [ ast:: ident ] ,
142
- extra_tps : [ ty:: param_bounds ] , m : @ast:: method ) -> ValueRef {
143
- let real_fn = ccx. item_ids . get ( m. id ) ;
146
+ fn trans_vtable ( ccx : @crate_ctxt , id : ast:: node_id , name : str ,
147
+ ptrs : [ ValueRef ] ) {
148
+ let tbl = C_struct ( ptrs) ;
149
+ let vt_gvar = str:: as_buf ( name, { |buf|
150
+ llvm:: LLVMAddGlobal ( ccx. llmod , val_ty ( tbl) , buf)
151
+ } ) ;
152
+ llvm:: LLVMSetInitializer ( vt_gvar, tbl) ;
153
+ llvm:: LLVMSetGlobalConstant ( vt_gvar, lib:: llvm:: True ) ;
154
+ ccx. item_ids . insert ( id, vt_gvar) ;
155
+ ccx. item_symbols . insert ( id, name) ;
156
+ }
157
+
158
+ fn trans_wrapper ( ccx : @crate_ctxt , pt : [ ast:: ident ] , llfty : TypeRef ,
159
+ fill : block ( ValueRef , @block_ctxt ) -> @block_ctxt )
160
+ -> ValueRef {
161
+ let lcx = @{ path: pt, module_path: [ ] ,
162
+ obj_typarams: [ ] , obj_fields: [ ] , ccx: ccx} ;
163
+ let name = link:: mangle_internal_name_by_path ( ccx, pt) ;
164
+ let llfn = decl_internal_cdecl_fn ( ccx. llmod , name, llfty) ;
165
+ let fcx = new_fn_ctxt ( lcx, ast_util:: dummy_sp ( ) , llfn) ;
166
+ let bcx = new_top_block_ctxt ( fcx) , lltop = bcx. llbb ;
167
+ let bcx = fill ( llfn, bcx) ;
168
+ build_return ( bcx) ;
169
+ finish_fn ( fcx, lltop) ;
170
+ ret llfn;
171
+ }
172
+
173
+ fn trans_impl_wrapper ( ccx : @crate_ctxt , pt : [ ast:: ident ] ,
174
+ extra_tps : [ ty:: param_bounds ] , real_fn : ValueRef )
175
+ -> ValueRef {
144
176
let { inputs: real_args , output: real_ret} =
145
177
llfn_arg_tys ( llvm:: LLVMGetElementType ( val_ty ( real_fn) ) ) ;
146
178
let extra_ptrs = [ ] ;
@@ -159,32 +191,80 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
159
191
let wrap_args = [ T_ptr ( T_dict ( ) ) ] + vec:: slice ( real_args, 0 u, 2 u) +
160
192
vec:: slice ( real_args, 2 u + vec:: len ( extra_ptrs) , vec:: len ( real_args) ) ;
161
193
let llfn_ty = T_fn ( wrap_args, real_ret) ;
194
+ trans_wrapper ( ccx, pt, llfn_ty, { |llfn, bcx|
195
+ let dict = PointerCast ( bcx, LLVMGetParam ( llfn, 0 u) , env_ty) ;
196
+ // retptr, self
197
+ let args = [ LLVMGetParam ( llfn, 1 u) , LLVMGetParam ( llfn, 2 u) ] , i = 0 u;
198
+ // saved tydescs/dicts
199
+ while i < n_extra_ptrs {
200
+ i += 1 u;
201
+ args += [ load_inbounds ( bcx, dict, [ 0 , i as int ] ) ] ;
202
+ }
203
+ // the rest of the parameters
204
+ let i = 3 u, params_total = llvm:: LLVMCountParamTypes ( llfn_ty) ;
205
+ while i < params_total {
206
+ args += [ LLVMGetParam ( llfn, i) ] ;
207
+ i += 1 u;
208
+ }
209
+ Call ( bcx, real_fn, args) ;
210
+ bcx
211
+ } )
212
+ }
162
213
163
- let lcx = @{ path: pt + [ "wrapper" , m. ident ] , module_path: [ ] ,
164
- obj_typarams: [ ] , obj_fields: [ ] , ccx: ccx} ;
165
- let name = link:: mangle_internal_name_by_path_and_seq ( ccx, pt, m. ident ) ;
166
- let llfn = decl_internal_cdecl_fn ( ccx. llmod , name, llfn_ty) ;
167
- let fcx = new_fn_ctxt ( lcx, ast_util:: dummy_sp ( ) , llfn) ;
168
- let bcx = new_top_block_ctxt ( fcx) , lltop = bcx. llbb ;
214
+ fn trans_impl_vtable ( ccx : @crate_ctxt , pt : [ ast:: ident ] ,
215
+ iface_id : ast:: def_id , ms : [ @ast:: method ] ,
216
+ tps : [ ast:: ty_param ] , it : @ast:: item ) {
217
+ let new_pt = pt + [ it. ident + int:: str ( it. id ) , "wrap" ] ;
218
+ let extra_tps = vec:: map ( tps, { |p| param_bounds ( ccx, p) } ) ;
219
+ let ptrs = vec:: map ( * ty:: iface_methods ( ccx. tcx , iface_id) , { |im|
220
+ alt vec:: find ( ms, { |m| m. ident == im. ident } ) {
221
+ some ( m) {
222
+ let target = ccx. item_ids . get ( m. id ) ;
223
+ trans_impl_wrapper ( ccx, new_pt + [ m. ident ] , extra_tps, target)
224
+ }
225
+ }
226
+ } ) ;
227
+ let s = link:: mangle_internal_name_by_path ( ccx, new_pt + [ "!vtable" ] ) ;
228
+ trans_vtable ( ccx, it. id , s, ptrs) ;
229
+ }
169
230
170
- let dict = PointerCast ( bcx, LLVMGetParam ( llfn, 0 u) , env_ty) ;
171
- // retptr, self
172
- let args = [ LLVMGetParam ( llfn, 1 u) , LLVMGetParam ( llfn, 2 u) ] , i = 0 u;
173
- // saved tydescs/dicts
174
- while i < n_extra_ptrs {
175
- i += 1 u;
176
- args += [ load_inbounds ( bcx, dict, [ 0 , i as int ] ) ] ;
177
- }
178
- // the rest of the parameters
179
- let i = 3 u, params_total = llvm:: LLVMCountParamTypes ( llfn_ty) ;
180
- while i < params_total {
181
- args += [ LLVMGetParam ( llfn, i) ] ;
231
+ fn trans_iface_wrapper ( ccx : @crate_ctxt , pt : [ ast:: ident ] , m : ty:: method ,
232
+ n : uint ) -> ValueRef {
233
+ let { llty: llfty , _} = wrapper_fn_ty ( ccx, T_ptr ( T_i8 ( ) ) , m) ;
234
+ trans_wrapper ( ccx, pt, llfty, { |llfn, bcx|
235
+ let self = Load ( bcx, PointerCast ( bcx, LLVMGetParam ( llfn, 2 u) ,
236
+ T_ptr ( T_opaque_iface_ptr ( ccx) ) ) ) ;
237
+ let boxed = GEPi ( bcx, self , [ 0 , abi:: box_rc_field_body] ) ;
238
+ let dict = Load ( bcx, PointerCast ( bcx, GEPi ( bcx, boxed, [ 0 , 1 ] ) ,
239
+ T_ptr ( T_ptr ( T_dict ( ) ) ) ) ) ;
240
+ let vtable = PointerCast ( bcx, Load ( bcx, GEPi ( bcx, dict, [ 0 , 0 ] ) ) ,
241
+ T_ptr ( T_array ( T_ptr ( llfty) , n + 1 u) ) ) ;
242
+ let mptr = Load ( bcx, GEPi ( bcx, vtable, [ 0 , n as int ] ) ) ;
243
+ // FIXME[impl] This doesn't account for more-than-ptr-sized alignment
244
+ let inner_self = GEPi ( bcx, boxed, [ 0 , 2 ] ) ;
245
+ let args = [ PointerCast ( bcx, dict, T_ptr ( T_i8 ( ) ) ) ,
246
+ LLVMGetParam ( llfn, 1 u) ,
247
+ PointerCast ( bcx, inner_self, T_opaque_cbox_ptr ( ccx) ) ] ;
248
+ let i = 3 u, total = llvm:: LLVMCountParamTypes ( llfty) ;
249
+ while i < total {
250
+ args += [ LLVMGetParam ( llfn, i) ] ;
251
+ i += 1 u;
252
+ }
253
+ Call ( bcx, mptr, args) ;
254
+ bcx
255
+ } )
256
+ }
257
+
258
+ fn trans_iface_vtable ( ccx : @crate_ctxt , pt : [ ast:: ident ] , it : @ast:: item ) {
259
+ let new_pt = pt + [ it. ident + int:: str ( it. id ) ] ;
260
+ let i_did = ast_util:: local_def ( it. id ) , i = 0 u;
261
+ let ptrs = vec:: map ( * ty:: iface_methods ( ccx. tcx , i_did) , { |m|
262
+ let w = trans_iface_wrapper ( ccx, new_pt + [ m. ident ] , m, i) ;
182
263
i += 1 u;
183
- }
184
- Call ( bcx, ccx. item_ids . get ( m. id ) , args) ;
185
- build_return ( bcx) ;
186
- finish_fn ( fcx, lltop) ;
187
- ret llfn;
264
+ w
265
+ } ) ;
266
+ let s = link:: mangle_internal_name_by_path ( ccx, new_pt + [ "!vtable" ] ) ;
267
+ trans_vtable ( ccx, it. id , s, ptrs) ;
188
268
}
189
269
190
270
fn dict_is_static ( tcx : ty:: ctxt , origin : typeck:: dict_origin ) -> bool {
@@ -193,7 +273,8 @@ fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
193
273
vec:: all ( ts, { |t| !ty:: type_contains_params ( tcx, t) } ) &&
194
274
vec:: all ( * origs, { |o| dict_is_static ( tcx, o) } )
195
275
}
196
- typeck:: dict_param ( _, _) { false }
276
+ typeck:: dict_iface ( _) { true }
277
+ _ { false }
197
278
}
198
279
}
199
280
@@ -219,14 +300,17 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
219
300
typeck:: dict_param( n_param, n_bound) {
220
301
rslt( bcx, option : : get ( bcx. fcx . lltyparams [ n_param] . dicts ) [ n_bound] )
221
302
}
303
+ typeck:: dict_iface ( did) {
304
+ ret rslt ( bcx, get_static_dict ( bcx, origin) ) ;
305
+ }
222
306
}
223
307
}
224
308
225
309
fn dict_id ( tcx : ty:: ctxt , origin : typeck:: dict_origin ) -> dict_id {
226
310
alt origin {
227
311
typeck : : dict_static ( did, ts, origs) {
228
312
let d_params = [ ] , orig = 0 u;
229
- if vec:: len ( ts) == 0 u { ret @{ impl_def : did, params : d_params} ; }
313
+ if vec:: len ( ts) == 0 u { ret @{ def : did, params : d_params} ; }
230
314
let impl_params = ty:: lookup_item_type ( tcx, did) . bounds ;
231
315
vec:: iter2 ( ts, * impl_params) { |t, bounds|
232
316
d_params += [ dict_param_ty ( t) ] ;
@@ -239,7 +323,10 @@ fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
239
323
}
240
324
}
241
325
}
242
- @{ impl_def: did, params: d_params}
326
+ @{ def: did, params: d_params}
327
+ }
328
+ typeck:: dict_iface ( did) {
329
+ @{ def: did, params: [ ] }
243
330
}
244
331
}
245
332
}
@@ -269,16 +356,19 @@ fn get_static_dict(bcx: @block_ctxt, origin: typeck::dict_origin)
269
356
fn get_dict_ptrs( bcx : @block_ctxt , origin : typeck:: dict_origin )
270
357
-> { bcx : @block_ctxt , ptrs : [ ValueRef ] } {
271
358
let ccx = bcx_ccx ( bcx) ;
272
- alt origin {
273
- typeck : : dict_static ( impl_did, tys, sub_origins) {
274
- let vtable = if impl_did. crate == ast:: local_crate {
275
- ccx. item_ids . get ( impl_did. node )
359
+ fn get_vtable ( ccx : @crate_ctxt , did : ast:: def_id ) -> ValueRef {
360
+ if did. crate == ast:: local_crate {
361
+ ccx. item_ids . get ( did. node )
276
362
} else {
277
- let name = csearch:: get_symbol ( ccx. sess . get_cstore ( ) , impl_did ) ;
363
+ let name = csearch:: get_symbol ( ccx. sess . get_cstore ( ) , did ) ;
278
364
get_extern_const ( ccx. externs , ccx. llmod , name, T_ptr ( T_i8 ( ) ) )
279
- } ;
365
+ }
366
+ }
367
+ alt origin {
368
+ typeck : : dict_static ( impl_did, tys, sub_origins) {
280
369
let impl_params = ty:: lookup_item_type ( ccx. tcx , impl_did) . bounds ;
281
- let ptrs = [ vtable] , origin = 0 u, ti = none, bcx = bcx;
370
+ let ptrs = [ get_vtable ( ccx, impl_did) ] ;
371
+ let origin = 0 u, ti = none, bcx = bcx;
282
372
vec:: iter2 ( * impl_params, tys) { |param, ty|
283
373
let rslt = get_tydesc ( bcx, ty, true , tps_normal, ti) . result ;
284
374
ptrs += [ rslt. val ] ;
@@ -297,6 +387,9 @@ fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
297
387
}
298
388
{ bcx: bcx, ptrs: ptrs}
299
389
}
390
+ typeck:: dict_iface ( did) {
391
+ { bcx: bcx, ptrs: [ get_vtable ( ccx, did) ] }
392
+ }
300
393
}
301
394
}
302
395
0 commit comments