@@ -5,8 +5,38 @@ import option::{some, none};
5
5
import syntax:: { ast, ast_util} ;
6
6
import metadata:: csearch;
7
7
import back:: link;
8
- import lib:: llvm;
9
- import llvm:: llvm:: { ValueRef , TypeRef , LLVMGetParam } ;
8
+ import lib:: llvm:: llvm;
9
+ import llvm:: { ValueRef , TypeRef , LLVMGetParam } ;
10
+
11
+ // Translation functionality related to impls and ifaces
12
+ //
13
+ // Terminology:
14
+ // vtable: a table of function pointers pointing to method wrappers
15
+ // of an impl that implements an iface
16
+ // dict: a record containing a vtable pointer along with pointers to
17
+ // all tydescs and other dicts needed to run methods in this vtable
18
+ // (i.e. corresponding to the type parameters of the impl)
19
+ // wrapper: a function that takes a dict as first argument, along
20
+ // with the method-specific tydescs for a method (and all
21
+ // other args the method expects), which fetches the extra
22
+ // tydescs and dicts from the dict, splices them into the
23
+ // arglist, and calls through to the actual method
24
+ //
25
+ // Generic functions take, along with their normal arguments, a number
26
+ // of extra tydesc and dict arguments -- one tydesc for each type
27
+ // parameter, one dict (following the tydesc in the arg order) for
28
+ // each interface bound on a type parameter.
29
+ //
30
+ // Most dicts are completely static, and are allocated and filled at
31
+ // compile time. Dicts that depend on run-time values (tydescs or
32
+ // dicts for type parameter types) are built at run-time, and interned
33
+ // through upcall_intern_dict in the runtime. This means that dict
34
+ // pointers are self-contained things that do not need to be cleaned
35
+ // up.
36
+ //
37
+ // The trans_constants pass in trans.rs outputs the vtables. Typeck
38
+ // annotates notes with information about the methods and dicts that
39
+ // are referenced (ccx.method_map and ccx.dict_map).
10
40
11
41
fn trans_impl ( cx : @local_ctxt , name : ast:: ident , methods : [ @ast:: method ] ,
12
42
id : ast:: node_id , tps : [ ast:: ty_param ] ) {
@@ -55,7 +85,8 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
55
85
let generic = none;
56
86
if vec:: len ( * method. tps ) > 0 u {
57
87
let tydescs = [ ] , tis = [ ] ;
58
- for t in ty:: node_id_to_type_params ( tcx, e. id ) {
88
+ let tptys = ty:: node_id_to_type_params ( tcx, e. id ) ;
89
+ for t in vec:: tail_n ( tptys, vec:: len ( tptys) - vec:: len ( * method. tps ) ) {
59
90
// TODO: Doesn't always escape.
60
91
let ti = none;
61
92
let td = get_tydesc ( bcx, t, true , tps_normal, ti) . result ;
@@ -75,18 +106,18 @@ fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
75
106
}
76
107
77
108
fn llfn_arg_tys ( ft : TypeRef ) -> { inputs : [ TypeRef ] , output : TypeRef } {
78
- let out_ty = llvm:: llvm :: LLVMGetReturnType ( ft) ;
79
- let n_args = llvm:: llvm :: LLVMCountParamTypes ( ft) ;
109
+ let out_ty = llvm:: LLVMGetReturnType ( ft) ;
110
+ let n_args = llvm:: LLVMCountParamTypes ( ft) ;
80
111
let args = vec:: init_elt ( 0 as TypeRef , n_args) ;
81
- unsafe { llvm:: llvm :: LLVMGetParamTypes ( ft, vec:: to_ptr ( args) ) ; }
112
+ unsafe { llvm:: LLVMGetParamTypes ( ft, vec:: to_ptr ( args) ) ; }
82
113
{ inputs: args, output: out_ty}
83
114
}
84
115
85
116
fn trans_wrapper ( ccx : @crate_ctxt , pt : [ ast:: ident ] ,
86
117
extra_tps : [ ty:: param_bounds ] , m : @ast:: method ) -> ValueRef {
87
118
let real_fn = ccx. item_ids . get ( m. id ) ;
88
119
let { inputs: real_args , output: real_ret} =
89
- llfn_arg_tys ( llvm:: llvm :: LLVMGetElementType ( val_ty ( real_fn) ) ) ;
120
+ llfn_arg_tys ( llvm:: LLVMGetElementType ( val_ty ( real_fn) ) ) ;
90
121
let extra_ptrs = [ ] ;
91
122
for tp in extra_tps {
92
123
extra_ptrs += [ T_ptr ( ccx. tydesc_type ) ] ;
@@ -120,7 +151,7 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
120
151
args += [ load_inbounds ( bcx, dict, [ 0 , i as int ] ) ] ;
121
152
}
122
153
// the rest of the parameters
123
- let i = 3 u, params_total = llvm:: llvm :: LLVMCountParamTypes ( llfn_ty) ;
154
+ let i = 3 u, params_total = llvm:: LLVMCountParamTypes ( llfn_ty) ;
124
155
while i < params_total {
125
156
args += [ LLVMGetParam ( llfn, i) ] ;
126
157
i += 1 u;
@@ -131,9 +162,88 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
131
162
ret llfn;
132
163
}
133
164
134
- // FIXME[impl] cache these on the function level somehow
165
+ fn dict_is_static ( tcx : ty:: ctxt , origin : typeck:: dict_origin ) -> bool {
166
+ alt origin {
167
+ typeck : : dict_static ( _, ts, origs) {
168
+ vec:: all ( ts, { |t| !ty:: type_contains_params ( tcx, t) } ) &&
169
+ vec:: all ( * origs, { |o| dict_is_static ( tcx, o) } )
170
+ }
171
+ typeck:: dict_param ( _, _) { false }
172
+ }
173
+ }
174
+
135
175
fn get_dict ( bcx : @block_ctxt , origin : typeck:: dict_origin ) -> result {
136
- let bcx = bcx, ccx = bcx_ccx ( bcx) ;
176
+ let ccx = bcx_ccx ( bcx) ;
177
+ alt origin {
178
+ typeck : : dict_static ( impl_did, tys, sub_origins) {
179
+ if dict_is_static ( ccx. tcx , origin) {
180
+ ret rslt ( bcx, get_static_dict ( bcx, origin) ) ;
181
+ }
182
+ let { bcx, ptrs} = get_dict_ptrs ( bcx, origin) ;
183
+ let pty = T_ptr ( T_i8 ( ) ) , dict_ty = T_array ( pty, vec:: len ( ptrs) ) ;
184
+ let dict = alloca ( bcx, dict_ty) , i = 0 ;
185
+ for ptr in ptrs {
186
+ Store ( bcx, PointerCast ( bcx, ptr, pty) , GEPi ( bcx, dict, [ 0 , i] ) ) ;
187
+ i += 1 ;
188
+ }
189
+ dict = Call ( bcx, ccx. upcalls . intern_dict ,
190
+ [ C_uint ( ccx, vec:: len ( ptrs) ) ,
191
+ PointerCast ( bcx, dict, T_ptr ( T_dict ( ) ) ) ] ) ;
192
+ rslt ( bcx, dict)
193
+ }
194
+ typeck:: dict_param( n_param, n_bound) {
195
+ rslt( bcx, option : : get ( bcx. fcx . lltyparams [ n_param] . dicts ) [ n_bound] )
196
+ }
197
+ }
198
+ }
199
+
200
+ fn dict_id ( tcx : ty:: ctxt , origin : typeck:: dict_origin ) -> dict_id {
201
+ alt origin {
202
+ typeck : : dict_static ( did, ts, origs) {
203
+ let d_params = [ ] , orig = 0 u;
204
+ if vec:: len ( ts) == 0 u { ret @{ impl_def : did, params : d_params} ; }
205
+ let impl_params = ty:: lookup_item_type ( tcx, did) . bounds ;
206
+ vec:: iter2 ( ts, * impl_params) { |t, bounds|
207
+ d_params += [ dict_param_ty ( t) ] ;
208
+ for bound in * bounds {
209
+ alt bound {
210
+ ty : : bound_iface ( _) {
211
+ d_params += [ dict_param_dict ( dict_id ( tcx, origs[ orig] ) ) ] ;
212
+ orig += 1 u;
213
+ }
214
+ }
215
+ }
216
+ }
217
+ @{ impl_def: did, params: d_params}
218
+ }
219
+ }
220
+ }
221
+
222
+ fn get_static_dict ( bcx : @block_ctxt , origin : typeck:: dict_origin )
223
+ -> ValueRef {
224
+ let ccx = bcx_ccx ( bcx) ;
225
+ let id = dict_id ( ccx. tcx , origin) ;
226
+ alt ccx. dicts . find ( id) {
227
+ some ( d) { ret d; }
228
+ none. { }
229
+ }
230
+ let ptrs = C_struct ( get_dict_ptrs ( bcx, origin) . ptrs ) ;
231
+ let name = ccx. names . next ( "dict" ) ;
232
+ let gvar = str:: as_buf ( name, { |buf|
233
+ llvm:: LLVMAddGlobal ( ccx. llmod , val_ty ( ptrs) , buf)
234
+ } ) ;
235
+ llvm:: LLVMSetGlobalConstant ( gvar, lib:: llvm:: True ) ;
236
+ llvm:: LLVMSetInitializer ( gvar, ptrs) ;
237
+ llvm:: LLVMSetLinkage ( gvar,
238
+ lib:: llvm:: LLVMInternalLinkage as llvm:: Linkage ) ;
239
+ let cast = llvm:: LLVMConstPointerCast ( gvar, T_ptr ( T_dict ( ) ) ) ;
240
+ ccx. dicts . insert ( id, cast) ;
241
+ cast
242
+ }
243
+
244
+ fn get_dict_ptrs( bcx : @block_ctxt , origin : typeck:: dict_origin )
245
+ -> { bcx : @block_ctxt , ptrs : [ ValueRef ] } {
246
+ let ccx = bcx_ccx ( bcx) ;
137
247
alt origin {
138
248
typeck : : dict_static ( impl_did, tys, sub_origins) {
139
249
let vtable = if impl_did. crate == ast:: local_crate {
@@ -143,9 +253,9 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
143
253
get_extern_const ( ccx. externs , ccx. llmod , name, T_ptr ( T_i8 ( ) ) )
144
254
} ;
145
255
let impl_params = ty:: lookup_item_type ( ccx. tcx , impl_did) . bounds ;
146
- let ptrs = [ vtable] , i = 0 u, origin = 0 u , ti = none ;
147
- for param in * impl_params {
148
- let rslt = get_tydesc ( bcx, tys [ i ] , false , tps_normal, ti) . result ;
256
+ let ptrs = [ vtable] , origin = 0 u, ti = none , bcx = bcx ;
257
+ vec :: iter2 ( * impl_params, tys ) { |param , ty|
258
+ let rslt = get_tydesc ( bcx, ty , true , tps_normal, ti) . result ;
149
259
ptrs += [ rslt. val ] ;
150
260
bcx = rslt. bcx ;
151
261
for bound in * param {
@@ -159,18 +269,8 @@ fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
159
269
_ { }
160
270
}
161
271
}
162
- i += 1 u;
163
272
}
164
- let pty = T_ptr ( T_i8 ( ) ) , dict_ty = T_array ( pty, vec:: len ( ptrs) ) ;
165
- let dict = alloca ( bcx, dict_ty) , i = 0 ;
166
- for ptr in ptrs {
167
- Store ( bcx, PointerCast ( bcx, ptr, pty) , GEPi ( bcx, dict, [ 0 , i] ) ) ;
168
- i += 1 ;
169
- }
170
- rslt ( bcx, PointerCast ( bcx, dict, T_ptr ( T_dict ( ) ) ) )
171
- }
172
- typeck:: dict_param ( n_param, n_bound) {
173
- rslt ( bcx, option:: get ( bcx. fcx . lltyparams [ n_param] . dicts ) [ n_bound] )
273
+ { bcx: bcx, ptrs: ptrs}
174
274
}
175
275
}
176
- }
276
+ }
0 commit comments