@@ -23,26 +23,26 @@ import trans::*;
23
23
export trans_anon_obj;
24
24
export trans_obj;
25
25
26
- // trans_obj: creates an LLVM function that is the object constructor for the
26
+ // trans_obj: create an LLVM function that is the object constructor for the
27
27
// object being translated.
28
28
fn trans_obj ( cx : @local_ctxt , sp : & span , ob : & ast:: _obj ,
29
29
ctor_id : ast:: node_id , ty_params : & [ ast:: ty_param ] ) {
30
+
30
31
// To make a function, we have to create a function context and, inside
31
32
// that, a number of block contexts for which code is generated.
32
-
33
33
let ccx = cx. ccx ;
34
34
let llctor_decl;
35
35
alt ccx. item_ids . find ( ctor_id) {
36
36
some ( x) { llctor_decl = x; }
37
37
_ { cx. ccx . sess . span_fatal ( sp, "unbound llctor_decl in trans_obj" ) ; }
38
38
}
39
+
39
40
// Much like trans_fn, we must create an LLVM function, but since we're
40
41
// starting with an ast::_obj rather than an ast::_fn, we have some setup
41
42
// work to do.
42
43
43
44
// The fields of our object will become the arguments to the function
44
45
// we're creating.
45
-
46
46
let fn_args: [ ast:: arg ] = ~[ ] ;
47
47
for f: ast:: obj_field in ob. fields {
48
48
fn_args +=
@@ -93,10 +93,6 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
93
93
// Next we have to take care of the other half of the pair we're
94
94
// returning: a boxed (reference-counted) tuple containing a tydesc,
95
95
// typarams, and fields.
96
-
97
- // FIXME: What about inner_obj? Do we have to think about it here?
98
- // (Pertains to issues #538/#539/#540/#543.)
99
-
100
96
let llbox_ty: TypeRef = T_ptr ( T_empty_struct ( ) ) ;
101
97
102
98
if std:: ivec:: len[ ast:: ty_param] ( ty_params) == 0 u &&
@@ -122,7 +118,8 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
122
118
// Tuple type for typarams: [typaram, ...]
123
119
let typarams_ty: ty:: t = ty:: mk_imm_tup ( ccx. tcx , tps) ;
124
120
125
- // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]]
121
+ // Tuple type for body:
122
+ // [tydesc_ty, [typaram, ...], [field, ...]]
126
123
let body_ty: ty:: t =
127
124
ty:: mk_imm_tup ( ccx. tcx , ~[ tydesc_ty, typarams_ty, fields_ty] ) ;
128
125
@@ -215,12 +212,10 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
215
212
fn trans_anon_obj ( bcx : @block_ctxt , sp : & span , anon_obj : & ast:: anon_obj ,
216
213
id : ast:: node_id ) -> result {
217
214
218
-
219
215
let ccx = bcx_ccx ( bcx) ;
220
216
221
- // Fields.
222
- // FIXME (part of issue #538): Where do we fill in the field *values* from
223
- // the outer object?
217
+ // Fields. FIXME (part of issue #538): Where do we fill in the field
218
+ // *values* from the outer object?
224
219
let additional_fields: [ ast:: anon_obj_field ] = ~[ ] ;
225
220
let additional_field_vals: [ result ] = ~[ ] ;
226
221
let additional_field_tys: [ ty:: t ] = ~[ ] ;
@@ -254,32 +249,31 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
254
249
let vtbl;
255
250
alt anon_obj. inner_obj {
256
251
none. {
257
- // We need a dummy inner_obj_ty for setting up the object body
258
- // later.
252
+ // We need a dummy inner_obj_ty for setting up the object body later.
259
253
inner_obj_ty = ty:: mk_type ( ccx. tcx ) ;
260
254
261
- // If there's no inner_obj -- that is, if we're just adding new
262
- // fields rather than extending an existing object -- then we just
263
- // pass the outer object to create_vtbl(). Our vtable won't need
255
+ // If there's no inner_obj -- that is, if we're creating a new object
256
+ // from nothing rather than extending an existing object -- then we
257
+ // just pass the outer object to create_vtbl(). Our vtable won't need
264
258
// to have any forwarding slots.
265
259
vtbl =
266
260
create_vtbl ( bcx. fcx . lcx , sp, outer_obj_ty, wrapper_obj, ~[ ] , none,
267
261
additional_field_tys) ;
268
262
}
269
263
some ( e) {
270
- // TODO: What makes more sense to get the type of an expr --
271
- // calling ty::expr_ty(ccx.tcx, e) on it or calling
264
+ // TODO: What makes more sense to get the type of an expr -- calling
265
+ // ty::expr_ty(ccx.tcx, e) on it or calling
272
266
// ty::node_id_to_type(ccx.tcx, id) on its id?
273
267
inner_obj_ty = ty:: expr_ty ( ccx. tcx , e) ;
274
268
//inner_obj_ty = ty::node_id_to_type(ccx.tcx, e.id);
275
269
276
270
// If there's a inner_obj, we pass its type along to create_vtbl().
277
- // Part of what create_vtbl() will do is take the set difference
278
- // of methods defined on the original and methods being added.
279
- // For every method defined on the original that does *not* have
280
- // one with a matching name and type being added, we'll need to
281
- // create a forwarding slot. And, of course, we need to create a
282
- // normal vtable entry for every method being added.
271
+ // Part of what create_vtbl() will do is take the set difference of
272
+ // methods defined on the original and methods being added. For every
273
+ // method defined on the original that does *not* have one with a
274
+ // matching name and type being added, we'll need to create a
275
+ // forwarding slot. And, of course, we need to create a normal vtable
276
+ // entry for every method being added.
283
277
vtbl =
284
278
create_vtbl ( bcx. fcx . lcx , sp, outer_obj_ty, wrapper_obj, ~[ ] ,
285
279
some ( inner_obj_ty) , additional_field_tys) ;
@@ -294,8 +288,6 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
294
288
add_clean_temp ( bcx, pair, t) ;
295
289
296
290
// Grab onto the first and second elements of the pair.
297
- // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1
298
- // of 'pair'.
299
291
let pair_vtbl =
300
292
bcx. build . GEP ( pair, ~[ C_int ( 0 ) , C_int ( abi:: obj_field_vtbl) ] ) ;
301
293
let pair_box =
@@ -414,8 +406,8 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
414
406
// Used only inside create_vtbl and create_backwarding_vtbl to distinguish
415
407
// different kinds of slots we'll have to create.
416
408
tag vtbl_mthd {
417
- // Normal methods are complete AST nodes, but for forwarding methods,
418
- // the only information we'll have about them is their type.
409
+ // Normal methods are complete AST nodes, but for forwarding methods, the
410
+ // only information we'll have about them is their type.
419
411
normal_mthd( @ast : : method) ;
420
412
fwding_mthd ( @ty:: method) ;
421
413
}
@@ -443,8 +435,8 @@ fn vtbl_mthd_lteq(a: &vtbl_mthd, b: &vtbl_mthd) -> bool {
443
435
}
444
436
}
445
437
446
- // Used by create_vtbl to filter a list of methods to remove the ones that we
447
- // don't need forwarding slots for.
438
+ // filtering_fn: Used by create_vtbl to filter a list of methods to remove the
439
+ // ones that we don't need forwarding slots for.
448
440
fn filtering_fn ( cx : @local_ctxt , m : & vtbl_mthd ,
449
441
addtl_meths : [ @ast:: method ] ) ->
450
442
option:: t [ vtbl_mthd ] {
@@ -468,8 +460,8 @@ fn filtering_fn(cx: @local_ctxt, m: &vtbl_mthd,
468
460
}
469
461
}
470
462
471
- // Create a vtable for an object being translated. Returns a pointer into
472
- // read-only memory .
463
+ // create_vtbl: Create a vtable for a regular object or for an outer anonymous
464
+ // object, and return a pointer to it .
473
465
fn create_vtbl ( cx : @local_ctxt , sp : & span , outer_obj_ty : ty:: t ,
474
466
ob : & ast:: _obj , ty_params : & [ ast:: ty_param ] ,
475
467
inner_obj_ty : option:: t [ ty:: t ] ,
@@ -479,6 +471,9 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
479
471
480
472
alt inner_obj_ty {
481
473
none. {
474
+ // We're creating a vtable for a regular object, or for an anonymous
475
+ // object that doesn't extend an existing one.
476
+
482
477
// Sort and process all the methods.
483
478
let meths =
484
479
std:: sort:: ivector:: merge_sort[ @ast:: method]
@@ -490,24 +485,18 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
490
485
}
491
486
}
492
487
some ( inner_obj_ty) {
493
- // If this vtable is being created for an extended object, then the
494
- // vtable needs to contain 'forwarding slots' for methods that were on
495
- // the original object and are not being overridden by the extended
496
- // one. So, to find the set of methods that we need forwarding slots
497
- // for, we need to take the set difference of inner_obj_methods
498
- // (methods on the original object) and ob.methods (methods being
499
- // added, whether entirely new or overriding).
500
-
501
- // inner_obj_ty is the type of the inner object being forwarded to,
502
- // and "ob" is the wrapper object. We need to take apart
503
- // inner_obj_ty, which is the type of the object being forwarded to
504
- // (it had better have an object type with methods!) and put those
505
- // original methods onto the list of methods we need forwarding
506
- // methods for.
488
+ // We're creating a vtable for an anonymous object that extends an
489
+ // existing one.
490
+
491
+ // The vtable needs to contain 'forwarding slots' for any methods that
492
+ // were on the inner object and are not being overridden by the outer
493
+ // one. To find the set of methods that we need forwarding slots for,
494
+ // we take the set difference of { methods on the original object }
495
+ // and { methods being added, whether entirely new or overriding }.
507
496
508
497
let meths: [ vtbl_mthd ] = ~[ ] ;
509
498
510
- // Gather up methods on the original object in 'meths' .
499
+ // Gather up methods on the inner object.
511
500
alt ty:: struct ( cx. ccx . tcx , inner_obj_ty) {
512
501
ty:: ty_obj ( inner_obj_methods) {
513
502
for m: ty:: method in inner_obj_methods {
@@ -520,8 +509,8 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
520
509
}
521
510
}
522
511
523
- // Now, filter out any methods that we don't need forwarding slots
524
- // for, because they're being overridden.
512
+ // Filter out any methods that we don't need forwarding slots for
513
+ // because they're being overridden.
525
514
let f = bind filtering_fn ( cx, _, ob. methods ) ;
526
515
meths = std:: ivec:: filter_map[ vtbl_mthd, vtbl_mthd] ( f, meths) ;
527
516
@@ -534,6 +523,8 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
534
523
std:: sort:: ivector:: merge_sort[ vtbl_mthd]
535
524
( bind vtbl_mthd_lteq ( _, _) , meths) ;
536
525
526
+ // To create forwarding methods, we'll need a "backwarding" vtbl. See
527
+ // create_backwarding_vtbl and process_bkwding_method for details.
537
528
let backwarding_vtbl: ValueRef =
538
529
create_backwarding_vtbl ( cx, sp, inner_obj_ty, outer_obj_ty) ;
539
530
@@ -554,17 +545,12 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
554
545
}
555
546
}
556
547
557
- let vtbl = C_struct ( llmethods) ;
558
- let vtbl_name = mangle_internal_name_by_path ( cx. ccx , cx. path + ~[ "vtbl" ] ) ;
559
- let gvar =
560
- llvm:: LLVMAddGlobal ( cx. ccx . llmod , val_ty ( vtbl) , str:: buf ( vtbl_name) ) ;
561
- llvm:: LLVMSetInitializer ( gvar, vtbl) ;
562
- llvm:: LLVMSetGlobalConstant ( gvar, True ) ;
563
- llvm:: LLVMSetLinkage ( gvar,
564
- lib:: llvm:: LLVMInternalLinkage as llvm:: Linkage ) ;
565
- ret gvar;
548
+ ret finish_vtbl ( cx, llmethods, "vtbl" ) ;
566
549
}
567
550
551
+ // create_backwarding_vtbl: Create a vtable for the inner object of an
552
+ // anonymous object, so that any self-calls made from the inner object's
553
+ // methods get redirected appropriately.
568
554
fn create_backwarding_vtbl ( cx : @local_ctxt , sp : & span , inner_obj_ty : ty:: t ,
569
555
outer_obj_ty : ty:: t ) -> ValueRef {
570
556
@@ -591,28 +577,30 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, inner_obj_ty: ty::t,
591
577
592
578
// Methods should have already been sorted, so no need to do so again.
593
579
for m: ty:: method in meths {
594
- // We pass outer_obj_ty to process_fwding_mthd() because it's
595
- // the one being forwarded to.
580
+ // We pass outer_obj_ty to process_fwding_mthd() because it's the one
581
+ // being forwarded to.
596
582
llmethods += ~[ process_bkwding_mthd (
597
583
cx, sp, @m, ~[ ] , outer_obj_ty, ~[ ] ) ] ;
598
584
}
599
585
586
+ ret finish_vtbl ( cx, llmethods, "backwarding_vtbl" ) ;
587
+ }
588
+
589
+ // finish_vtbl: Given a vector of vtable entries, create the table in
590
+ // read-only memory and return a pointer to it.
591
+ fn finish_vtbl ( cx : @local_ctxt , llmethods : [ ValueRef ] , name : str )
592
+ -> ValueRef {
600
593
let vtbl = C_struct ( llmethods) ;
601
- let vtbl_name =
602
- mangle_internal_name_by_path ( cx. ccx ,
603
- cx. path + ~[ "backwarding_vtbl" ] ) ;
594
+ let vtbl_name = mangle_internal_name_by_path ( cx. ccx , cx. path + ~[ name] ) ;
604
595
let gvar =
605
596
llvm:: LLVMAddGlobal ( cx. ccx . llmod , val_ty ( vtbl) , str:: buf ( vtbl_name) ) ;
606
597
llvm:: LLVMSetInitializer ( gvar, vtbl) ;
607
598
llvm:: LLVMSetGlobalConstant ( gvar, True ) ;
608
599
llvm:: LLVMSetLinkage ( gvar,
609
600
lib:: llvm:: LLVMInternalLinkage as llvm:: Linkage ) ;
610
-
611
601
ret gvar;
612
-
613
602
}
614
603
615
-
616
604
// process_bkwding_mthd: Create the backwarding function that appears in a
617
605
// backwarding vtable slot.
618
606
//
@@ -653,9 +641,9 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
653
641
let bcx = new_top_block_ctxt ( fcx) ;
654
642
let lltop = bcx. llbb ;
655
643
656
- // The self-object will arrive in the backwarding function via the llenv
657
- // argument, but we need to jump past the first item in the self-stack to
658
- // get to the one we really want.
644
+ // The self-object will arrive in the backwarding function via the
645
+ // llenv argument, but we need to jump past the first item in the
646
+ // self-stack to get to the one we really want.
659
647
660
648
// Cast to self-stack's type.
661
649
let llenv = bcx. build . PointerCast (
@@ -717,8 +705,8 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
717
705
bcx. build . PointerCast ( llouter_mthd, T_ptr ( T_ptr ( llouter_mthd_ty) ) ) ;
718
706
llouter_mthd = bcx. build . Load ( llouter_mthd) ;
719
707
720
- // Set up the three implicit arguments to the outer method we'll need
721
- // to call.
708
+ // Set up the three implicit arguments to the outer method we'll need to
709
+ // call.
722
710
let self_arg = llself_obj_ptr;
723
711
let llouter_mthd_args: [ ValueRef ] = ~[ llretptr, fcx. lltaskptr , self_arg] ;
724
712
@@ -831,8 +819,7 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
831
819
// Placeholder for non-existent typarams, since anon objs don't have them.
832
820
let typarams_ty: ty:: t = ty:: mk_imm_tup ( cx. ccx . tcx , ~[ ] ) ;
833
821
834
- // Tuple type for body:
835
- // [tydesc, [typaram, ...], [field, ...], inner_obj]
822
+ // Tuple type for body: [tydesc, [typaram, ...], [field, ...], inner_obj]
836
823
837
824
let body_ty: ty:: t =
838
825
ty:: mk_imm_tup ( cx. ccx . tcx ,
@@ -951,9 +938,9 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
951
938
let s: str = mangle_internal_name_by_path ( mcx. ccx , mcx. path ) ;
952
939
let llfn: ValueRef = decl_internal_fastcall_fn ( cx. ccx . llmod , s, llfnty) ;
953
940
954
- // Every method on an object gets its node_id inserted into the
955
- // crate-wide item_ids map, together with the ValueRef that points to
956
- // where that method's definition will be in the executable.
941
+ // Every method on an object gets its node_id inserted into the crate-wide
942
+ // item_ids map, together with the ValueRef that points to where that
943
+ // method's definition will be in the executable.
957
944
cx. ccx . item_ids . insert ( m. node . id , llfn) ;
958
945
cx. ccx . item_symbols . insert ( m. node . id , s) ;
959
946
trans_fn ( mcx, m. span , m. node . meth , llfn, some ( self_ty) , ty_params,
@@ -999,3 +986,13 @@ fn populate_self_stack(bcx: @block_ctxt,
999
986
1000
987
ret self_stack;
1001
988
}
989
+ //
990
+ // Local Variables:
991
+ // mode: rust
992
+ // fill-column: 78;
993
+ // indent-tabs-mode: nil
994
+ // c-basic-offset: 4
995
+ // buffer-file-coding-system: utf-8-unix
996
+ // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
997
+ // End:
998
+ //
0 commit comments