@@ -283,23 +283,25 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
283
283
std::vector<llvm::Constant*> constants;
284
284
constants.reserve (vtbl_array.dim );
285
285
286
- // start with the interface info
287
- VarDeclarationIter interfaces_idx (ClassDeclaration::classinfo->fields , 3 );
286
+ if (!b->base ->isCPPinterface ()) { // skip interface info for CPP interfaces
287
+ // start with the interface info
288
+ VarDeclarationIter interfaces_idx (ClassDeclaration::classinfo->fields , 3 );
288
289
289
- // index into the interfaces array
290
- llvm::Constant* idxs[2 ] = {
291
- DtoConstSize_t (0 ),
292
- DtoConstSize_t (interfaces_index)
293
- };
290
+ // index into the interfaces array
291
+ llvm::Constant* idxs[2 ] = {
292
+ DtoConstSize_t (0 ),
293
+ DtoConstSize_t (interfaces_index)
294
+ };
294
295
295
- llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr (
296
- getInterfaceArraySymbol (), idxs, true );
296
+ llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr (
297
+ getInterfaceArraySymbol (), idxs, true );
297
298
298
- constants.push_back (c);
299
+ constants.push_back (c);
300
+ }
299
301
300
302
// add virtual function pointers
301
303
size_t n = vtbl_array.dim ;
302
- for (size_t i = 1 ; i < n; i++)
304
+ for (size_t i = b-> base -> vtblOffset () ; i < n; i++)
303
305
{
304
306
Dsymbol* dsym = static_cast <Dsymbol*>(vtbl_array.data [i]);
305
307
if (dsym == NULL )
@@ -320,7 +322,59 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
320
322
fd->codegen (Type::sir);
321
323
assert (fd->ir .irFunc && " invalid vtbl function" );
322
324
323
- constants.push_back (fd->ir .irFunc ->func );
325
+ LLFunction *fn = fd->ir .irFunc ->func ;
326
+
327
+ // If the base is a cpp interface, 'this' parameter is a pointer to
328
+ // the interface not the underlying object as expected. Instead of
329
+ // the function, we place into the vtable a small wrapper, called thunk,
330
+ // that casts 'this' to the object and then pass it to the real function.
331
+ if (b->base ->isCPPinterface ()) {
332
+ TypeFunction *f = (TypeFunction*)fd->type ->toBasetype ();
333
+ assert (f->fty .arg_this );
334
+
335
+ // create the thunk function
336
+ OutBuffer name;
337
+ name.writestring (" Th" );
338
+ name.printf (" %i" , b->offset );
339
+ name.writestring (fd->mangle ());
340
+ LLFunction *thunk = LLFunction::Create (isaFunction (fn->getType ()->getContainedType (0 )),
341
+ DtoLinkage (fd), name.toChars (), gIR ->module );
342
+
343
+ // create entry and end blocks
344
+ llvm::BasicBlock* beginbb = llvm::BasicBlock::Create (gIR ->context (), " entry" , thunk);
345
+ llvm::BasicBlock* endbb = llvm::BasicBlock::Create (gIR ->context (), " endentry" , thunk);
346
+ gIR ->scopes .push_back (IRScope (beginbb, endbb));
347
+
348
+ // copy the function parameters, so later we can pass them to the real function
349
+ std::vector<LLValue*> args;
350
+ llvm::Function::arg_iterator iarg = thunk->arg_begin ();
351
+ for (; iarg != thunk->arg_end (); ++iarg)
352
+ args.push_back (iarg);
353
+
354
+ // cast 'this' to Object
355
+ LLValue* &thisArg = args[(f->fty .arg_sret == 0 ) ? 0 : 1 ];
356
+ LLType* thisType = thisArg->getType ();
357
+ thisArg = DtoBitCast (thisArg, getVoidPtrType ());
358
+ thisArg = DtoGEP1 (thisArg, DtoConstInt (-b->offset ));
359
+ thisArg = DtoBitCast (thisArg, thisType);
360
+
361
+ // call the real vtbl function.
362
+ LLValue *retVal = gIR ->ir ->CreateCall (fn, args);
363
+
364
+ // return from the thunk
365
+ if (thunk->getReturnType () == LLType::getVoidTy (gIR ->context ()))
366
+ llvm::ReturnInst::Create (gIR ->context (), beginbb);
367
+ else
368
+ llvm::ReturnInst::Create (gIR ->context (), retVal, beginbb);
369
+
370
+ // clean up
371
+ gIR ->scopes .pop_back ();
372
+ thunk->getBasicBlockList ().pop_back ();
373
+
374
+ fn = thunk;
375
+ }
376
+
377
+ constants.push_back (fn);
324
378
}
325
379
326
380
// build the vtbl constant
0 commit comments