@@ -4196,45 +4196,17 @@ fn collect_upvars(&@block_ctxt cx, &ast::block bloc,
4196
4196
ret result;
4197
4197
}
4198
4198
4199
- fn trans_for_each( & @block_ctxt cx, & @ast:: local local, & @ast:: expr seq,
4200
- & ast:: block body) -> result {
4201
- /*
4202
- * The translation is a little .. complex here. Code like:
4203
- *
4204
- * let ty1 p = ...;
4205
- *
4206
- * let ty1 q = ...;
4207
- *
4208
- * foreach (ty v in foo(a,b)) { body(p,q,v) }
4209
- *
4210
- *
4211
- * Turns into a something like so (C/Rust mishmash):
4212
- *
4213
- * type env = { *ty1 p, *ty2 q, ... };
4214
- *
4215
- * let env e = { &p, &q, ... };
4216
- *
4217
- * fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
4218
- *
4219
- * foo([foreach123_body, env*], a, b);
4220
- *
4221
- */
4222
-
4223
- // Step 1: walk body and figure out which references it makes
4224
- // escape. This could be determined upstream, and probably ought
4225
- // to be so, eventualy.
4226
-
4227
- auto lcx = cx. fcx. lcx;
4228
- // FIXME: possibly support alias-mode here?
4229
-
4230
- auto decl_ty = node_id_type( lcx. ccx, local. node. id) ;
4231
- auto decl_id = local. node. id;
4232
- auto upvars = collect_upvars( cx, body, decl_id) ;
4199
+ // Given a block context and a list of upvars, construct a closure that
4200
+ // contains pointers to all of the upvars and all of the tydescs in
4201
+ // scope. Return the ValueRef and TypeRef corresponding to the closure.
4202
+ fn build_environment( & @block_ctxt cx, & vec[ ast:: node_id] upvars) ->
4203
+ tup( ValueRef , TypeRef )
4204
+ {
4233
4205
auto upvar_count = vec:: len( upvars) ;
4234
4206
auto llbindingsptr;
4207
+
4235
4208
if ( upvar_count > 0 u) {
4236
4209
// Gather up the upvars.
4237
-
4238
4210
let vec[ ValueRef ] llbindings = [ ] ;
4239
4211
let vec[ TypeRef ] llbindingtys = [ ] ;
4240
4212
for ( ast:: node_id nid in upvars) {
@@ -4253,8 +4225,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4253
4225
llbindings += [ llbinding] ;
4254
4226
llbindingtys += [ val_ty( llbinding) ] ;
4255
4227
}
4256
- // Create an array of bindings and copy in aliases to the upvars.
4257
4228
4229
+ // Create an array of bindings and copy in aliases to the upvars.
4258
4230
llbindingsptr = alloca( cx, T_struct ( llbindingtys) ) ;
4259
4231
auto i = 0 u;
4260
4232
while ( i < upvar_count) {
@@ -4265,23 +4237,22 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4265
4237
}
4266
4238
} else {
4267
4239
// Null bindings.
4268
-
4269
4240
llbindingsptr = C_null ( T_ptr ( T_i8 ( ) ) ) ;
4270
4241
}
4271
- // Create an environment and populate it with the bindings.
4272
4242
4243
+ // Create an environment and populate it with the bindings.
4273
4244
auto tydesc_count = vec:: len[ ValueRef ] ( cx. fcx. lltydescs) ;
4274
4245
auto llenvptrty =
4275
- T_closure_ptr ( lcx. ccx. tn, T_ptr ( T_nil ( ) ) , val_ty ( llbindingsptr ) ,
4276
- tydesc_count) ;
4246
+ T_closure_ptr ( cx . fcx . lcx. ccx. tn, T_ptr ( T_nil ( ) ) ,
4247
+ val_ty ( llbindingsptr ) , tydesc_count) ;
4277
4248
auto llenvptr = alloca( cx, llvm:: LLVMGetElementType ( llenvptrty) ) ;
4278
4249
auto llbindingsptrptr =
4279
4250
cx. build. GEP ( llenvptr,
4280
4251
[ C_int ( 0 ) , C_int ( abi:: box_rc_field_body) , C_int ( 2 ) ] ) ;
4281
4252
cx. build. Store ( llbindingsptr, llbindingsptrptr) ;
4253
+
4282
4254
// Copy in our type descriptors, in case the iterator body needs to refer
4283
4255
// to them.
4284
-
4285
4256
auto lltydescsptr =
4286
4257
cx. build. GEP ( llenvptr,
4287
4258
[ C_int ( 0 ) , C_int ( abi:: box_rc_field_body) ,
@@ -4293,16 +4264,58 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4293
4264
cx. build. Store ( cx. fcx. lltydescs. ( i) , lltydescptr) ;
4294
4265
i += 1 u;
4295
4266
}
4296
- // Step 2: Declare foreach body function.
4297
4267
4268
+ ret tup( llenvptr, llenvptrty) ;
4269
+ }
4270
+
4271
+ fn trans_for_each( & @block_ctxt cx, & @ast:: local local, & @ast:: expr seq,
4272
+ & ast:: block body) -> result {
4273
+ /*
4274
+ * The translation is a little .. complex here. Code like:
4275
+ *
4276
+ * let ty1 p = ...;
4277
+ *
4278
+ * let ty1 q = ...;
4279
+ *
4280
+ * foreach (ty v in foo(a,b)) { body(p,q,v) }
4281
+ *
4282
+ *
4283
+ * Turns into a something like so (C/Rust mishmash):
4284
+ *
4285
+ * type env = { *ty1 p, *ty2 q, ... };
4286
+ *
4287
+ * let env e = { &p, &q, ... };
4288
+ *
4289
+ * fn foreach123_body(env* e, ty v) { body(*(e->p),*(e->q),v) }
4290
+ *
4291
+ * foo([foreach123_body, env*], a, b);
4292
+ *
4293
+ */
4294
+
4295
+ // Step 1: walk body and figure out which references it makes
4296
+ // escape. This could be determined upstream, and probably ought
4297
+ // to be so, eventualy.
4298
+ auto lcx = cx. fcx. lcx;
4299
+
4300
+ // FIXME: possibly support alias-mode here?
4301
+ auto decl_ty = node_id_type( lcx. ccx, local. node. id) ;
4302
+ auto decl_id = local. node. id;
4303
+ auto upvars = collect_upvars( cx, body, decl_id) ;
4304
+ auto upvar_count = vec:: len( upvars) ;
4305
+
4306
+ auto environment_data = build_environment( cx, upvars) ;
4307
+ auto llenvptr = environment_data. _0;
4308
+ auto llenvptrty = environment_data. _1;
4309
+
4310
+ // Step 2: Declare foreach body function.
4298
4311
let str s =
4299
4312
mangle_internal_name_by_path_and_seq( lcx. ccx, lcx. path, "foreach") ;
4313
+
4300
4314
// The 'env' arg entering the body function is a fake env member (as in
4301
4315
// the env-part of the normal rust calling convention) that actually
4302
4316
// points to a stack allocated env in this frame. We bundle that env
4303
4317
// pointer along with the foreach-body-fn pointer into a 'normal' fn pair
4304
4318
// and pass it in as a first class fn-arg to the iterator.
4305
-
4306
4319
auto iter_body_llty =
4307
4320
type_of_fn_full( lcx. ccx, cx. sp, ast:: proto_fn, none[ TypeRef ] ,
4308
4321
[ rec( mode=ty:: mo_alias( false) , ty=decl_ty) ] ,
@@ -4311,8 +4324,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4311
4324
decl_internal_fastcall_fn( lcx. ccx. llmod, s, iter_body_llty) ;
4312
4325
auto fcx = new_fn_ctxt( lcx, cx. sp, lliterbody) ;
4313
4326
auto copy_args_bcx = new_raw_block_ctxt( fcx, fcx. llcopyargs) ;
4314
- // Populate the upvars from the environment.
4315
4327
4328
+ // Populate the upvars from the environment.
4316
4329
auto llremoteenvptr =
4317
4330
copy_args_bcx. build. PointerCast ( fcx. llenv, llenvptrty) ;
4318
4331
auto llremotebindingsptrptr =
@@ -4321,7 +4334,7 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4321
4334
C_int ( abi:: closure_elt_bindings) ] ) ;
4322
4335
auto llremotebindingsptr =
4323
4336
copy_args_bcx. build. Load ( llremotebindingsptrptr) ;
4324
- i = 0 u;
4337
+ auto i = 0 u;
4325
4338
while ( i < upvar_count) {
4326
4339
auto upvar_id = upvars. ( i) ;
4327
4340
auto llupvarptrptr =
@@ -4331,12 +4344,13 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4331
4344
fcx. llupvars. insert( upvar_id, llupvarptr) ;
4332
4345
i += 1 u;
4333
4346
}
4334
- // Populate the type parameters from the environment.
4335
4347
4348
+ // Populate the type parameters from the environment.
4336
4349
auto llremotetydescsptr =
4337
4350
copy_args_bcx. build. GEP ( llremoteenvptr,
4338
4351
[ C_int ( 0 ) , C_int ( abi:: box_rc_field_body) ,
4339
4352
C_int ( abi:: closure_elt_ty_params) ] ) ;
4353
+ auto tydesc_count = vec:: len[ ValueRef ] ( cx. fcx. lltydescs) ;
4340
4354
i = 0 u;
4341
4355
while ( i < tydesc_count) {
4342
4356
auto llremotetydescptr =
@@ -4346,8 +4360,8 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq,
4346
4360
fcx. lltydescs += [ llremotetydesc] ;
4347
4361
i += 1 u;
4348
4362
}
4349
- // Add an upvar for the loop variable alias.
4350
4363
4364
+ // Add an upvar for the loop variable alias.
4351
4365
fcx. llupvars. insert( decl_id, llvm:: LLVMGetParam ( fcx. llfn, 3 u) ) ;
4352
4366
auto bcx = new_top_block_ctxt( fcx) ;
4353
4367
auto lltop = bcx. llbb;
0 commit comments