@@ -6482,23 +6482,42 @@ fn trans_fn(cx: @local_ctxt, sp: &span, f: &ast::_fn, llfndecl: ValueRef,
6482
6482
}
6483
6483
6484
6484
// process_fwding_mthd: Create the forwarding function that appears in a
6485
- // vtable slot for method calls that "fall through" to an inner object. A
6485
+ // vtable slot for method calls that need to forward to another object. A
6486
6486
// helper function for create_vtbl.
6487
+ //
6488
+ // We use forwarding functions in two situations:
6489
+ //
6490
+ // (1) Forwarding: For method calls that fall through to an inner object, For
6491
+ // example, suppose an inner object has method foo and we extend it with
6492
+ // a method bar. The only version of 'foo' we have is on the inner
6493
+ // object, but we would like to be able to call outer.foo(). So we use a
6494
+ // forwarding function to make the foo method available on the outer
6495
+ // object. It takes all the same arguments as the foo method on the
6496
+ // inner object does, calls inner.foo() with those arguments, and then
6497
+ // returns the value returned from that call. (The inner object won't
6498
+ // exist until run-time, but we know its type statically.)
6499
+ //
6500
+ // (2) Backwarding: For method calls that dispatch back through an outer
6501
+ // object. For example, suppose an inner object has methods foo and bar,
6502
+ // and bar contains the call self.foo(). We extend that object with a
6503
+ // foo method that overrides the inner foo. Now, a call to outer.bar()
6504
+ // should send us to to inner.bar() via a normal forwarding function, and
6505
+ // then to self.foo(). But inner.bar() was already compiled under the
6506
+ // assumption that self.foo() is inner.foo(), when we really want to
6507
+ // reach outer.foo(). So, we give 'self' a vtable of backwarding
6508
+ // functions, one for each method on inner, each of which takes all the
6509
+ // same arguments as the corresponding method on inner does, calls that
6510
+ // method on outer, and returns the value returned from that call.
6511
+
6487
6512
fn process_fwding_mthd ( cx : @local_ctxt , sp : & span , m : @ty:: method ,
6488
- ty_params : & ast:: ty_param [ ] , inner_obj_ty : ty:: t ,
6513
+ ty_params : & ast:: ty_param [ ] , target_obj_ty : ty:: t ,
6489
6514
backwarding_vtbl : option:: t [ ValueRef ] ,
6490
6515
additional_field_tys : & ty:: t [ ] ) -> ValueRef {
6491
6516
6492
-
6493
- // The method m is being called on the outer object, but the outer object
6494
- // doesn't have that method; only the inner object does. So what we have
6495
- // to do is synthesize that method on the outer object. It has to take
6496
- // all the same arguments as the method on the inner object does, then
6497
- // call m with those arguments on the inner object, and then return the
6498
- // value returned from that call. It's like an eta-expansion around m,
6499
- // except we also have to pass the inner object that m should be called
6500
- // on. That object won't exist until run-time, but we know its type
6501
- // statically.
6517
+ // NB: target_obj_ty is the type of the object being forwarded to.
6518
+ // Depending on whether this is a forwarding or backwarding function, it
6519
+ // will be either the inner obj's type or the outer obj's type,
6520
+ // respectively.
6502
6521
6503
6522
// Create a local context that's aware of the name of the method we're
6504
6523
// creating.
@@ -6534,16 +6553,24 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
6534
6553
6535
6554
// Do backwarding if necessary.
6536
6555
alt ( backwarding_vtbl) {
6537
- none. { /* fall through */ }
6556
+ none. {
6557
+ // NB: As before, this means that we are processing a backwarding fn
6558
+ // right now.
6559
+ }
6538
6560
some ( bv) {
6539
- // Grab the vtable out of the self-object.
6561
+ // NB: As before, this means that we are processing a forwarding fn
6562
+ // right now.
6563
+
6564
+ // Grab the vtable out of the self-object and replace it with the
6565
+ // backwarding vtable.
6540
6566
let llself_obj_vtbl =
6541
6567
bcx. build . GEP ( llself_obj_ptr, ~[ C_int ( 0 ) ,
6542
6568
C_int ( abi:: obj_field_vtbl) ] ) ;
6543
-
6544
- // And replace it with the backwarding vtbl.
6545
6569
let llbv = bcx. build . PointerCast ( bv, T_ptr ( T_empty_struct ( ) ) ) ;
6546
6570
bcx. build . Store ( llbv, llself_obj_vtbl) ;
6571
+
6572
+ // NB: llself_obj is now a freakish combination of outer object body
6573
+ // and backwarding (inner-object) vtable.
6547
6574
}
6548
6575
}
6549
6576
@@ -6595,6 +6622,15 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
6595
6622
6596
6623
// Tuple type for body:
6597
6624
// [tydesc, [typaram, ...], [field, ...], inner_obj]
6625
+
6626
+ // NB: When we're creating a forwarding fn, target_obj_ty is indeed the
6627
+ // type of the inner object, so it makes sense to have 'target_obj_ty'
6628
+ // appear here. When we're creating a backwarding fn, though,
6629
+ // target_obj_ty is the outer object's type, so instead, we need to use
6630
+ // the extra inner type we passed along.
6631
+
6632
+ let inner_obj_ty = target_obj_ty;
6633
+
6598
6634
let body_ty: ty:: t =
6599
6635
ty:: mk_imm_tup ( cx. ccx . tcx ,
6600
6636
~[ tydesc_ty, typarams_ty, fields_ty, inner_obj_ty] ) ;
@@ -6621,14 +6657,14 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
6621
6657
6622
6658
// Get the index of the method we want.
6623
6659
let ix: uint = 0 u;
6624
- alt ty:: struct ( bcx_tcx ( bcx) , inner_obj_ty ) {
6660
+ alt ty:: struct ( bcx_tcx ( bcx) , target_obj_ty ) {
6625
6661
ty:: ty_obj ( methods) {
6626
6662
ix = ty:: method_idx ( cx. ccx . sess , sp, m. ident , methods) ;
6627
6663
}
6628
6664
_ {
6629
6665
// Shouldn't happen.
6630
6666
cx. ccx . sess . bug ( "process_fwding_mthd(): non-object type passed \
6631
- as inner_obj_ty ") ;
6667
+ as target_obj_ty ") ;
6632
6668
}
6633
6669
}
6634
6670
@@ -6652,7 +6688,8 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
6652
6688
6653
6689
// Set up the three implicit arguments to the original method we'll need
6654
6690
// to call.
6655
- let llorig_mthd_args: ValueRef [ ] = ~[ llretptr, fcx. lltaskptr , llself_obj] ;
6691
+ let self_arg = llself_obj;
6692
+ let llorig_mthd_args: ValueRef [ ] = ~[ llretptr, fcx. lltaskptr , self_arg] ;
6656
6693
6657
6694
// Copy the explicit arguments that are being passed into the forwarding
6658
6695
// function (they're in fcx.llargs) to llorig_mthd_args.
0 commit comments