Merge pull request #412 from AlexeyProkhin/cpp

extern(C++) interfaces
This commit is contained in:
Kai Nacke
2013-06-30 15:37:10 -07:00
4 changed files with 72 additions and 15 deletions

View File

@@ -513,8 +513,9 @@ LLValue* DtoVirtualFunctionPointer(DValue* inst, FuncDeclaration* fdecl, char* n
// sanity checks
assert(fdecl->isVirtual());
assert(!fdecl->isFinal());
assert(fdecl->vtblIndex > 0); // 0 is always ClassInfo/Interface*
assert(inst->getType()->toBasetype()->ty == Tclass);
// 0 is always ClassInfo/Interface* unless it is a CPP interface
assert(fdecl->vtblIndex > 0 || (fdecl->vtblIndex == 0 && fdecl->linkage == LINKcpp));
// get instance
LLValue* vthis = inst->getRVal();

View File

@@ -1496,11 +1496,13 @@ DValue* DotVarExp::toElem(IRState* p)
// If we are calling a non-final interface function, we need to get
// the pointer to the underlying object instead of passing the
// interface pointer directly.
// Unless it is a cpp interface, in that case, we have to match
// C++ behavior and pass the interface pointer.
LLValue* passedThis = 0;
if (e1type->ty == Tclass)
{
TypeClass* tc = static_cast<TypeClass*>(e1type);
if (tc->sym->isInterfaceDeclaration() && nonFinal)
if (tc->sym->isInterfaceDeclaration() && nonFinal && !tc->sym->isCPPinterface())
passedThis = DtoCastInterfaceToObject(l, NULL)->getRVal();
}
LLValue* vthis = l->getRVal();

View File

@@ -283,23 +283,25 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
std::vector<llvm::Constant*> constants;
constants.reserve(vtbl_array.dim);
// start with the interface info
VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces
// start with the interface info
VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
// index into the interfaces array
llvm::Constant* idxs[2] = {
DtoConstSize_t(0),
DtoConstSize_t(interfaces_index)
};
// index into the interfaces array
llvm::Constant* idxs[2] = {
DtoConstSize_t(0),
DtoConstSize_t(interfaces_index)
};
llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
getInterfaceArraySymbol(), idxs, true);
llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
getInterfaceArraySymbol(), idxs, true);
constants.push_back(c);
constants.push_back(c);
}
// add virtual function pointers
size_t n = vtbl_array.dim;
for (size_t i = 1; i < n; i++)
for (size_t i = b->base->vtblOffset(); i < n; i++)
{
Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]);
if (dsym == NULL)
@@ -320,7 +322,59 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
fd->codegen(Type::sir);
assert(fd->ir.irFunc && "invalid vtbl function");
constants.push_back(fd->ir.irFunc->func);
LLFunction *fn = fd->ir.irFunc->func;
// If the base is a cpp interface, 'this' parameter is a pointer to
// the interface not the underlying object as expected. Instead of
// the function, we place into the vtable a small wrapper, called thunk,
// that casts 'this' to the object and then pass it to the real function.
if (b->base->isCPPinterface()) {
TypeFunction *f = (TypeFunction*)fd->type->toBasetype();
assert(f->fty.arg_this);
// create the thunk function
OutBuffer name;
name.writestring("Th");
name.printf("%i", b->offset);
name.writestring(fd->mangle());
LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)),
DtoLinkage(fd), name.toChars(), gIR->module);
// create entry and end blocks
llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "entry", thunk);
llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", thunk);
gIR->scopes.push_back(IRScope(beginbb, endbb));
// copy the function parameters, so later we can pass them to the real function
std::vector<LLValue*> args;
llvm::Function::arg_iterator iarg = thunk->arg_begin();
for (; iarg != thunk->arg_end(); ++iarg)
args.push_back(iarg);
// cast 'this' to Object
LLValue* &thisArg = args[(f->fty.arg_sret == 0) ? 0 : 1];
LLType* thisType = thisArg->getType();
thisArg = DtoBitCast(thisArg, getVoidPtrType());
thisArg = DtoGEP1(thisArg, DtoConstInt(-b->offset));
thisArg = DtoBitCast(thisArg, thisType);
// call the real vtbl function.
LLValue *retVal = gIR->ir->CreateCall(fn, args);
// return from the thunk
if (thunk->getReturnType() == LLType::getVoidTy(gIR->context()))
llvm::ReturnInst::Create(gIR->context(), beginbb);
else
llvm::ReturnInst::Create(gIR->context(), retVal, beginbb);
// clean up
gIR->scopes.pop_back();
thunk->getBasicBlockList().pop_back();
fn = thunk;
}
constants.push_back(fn);
}
// build the vtbl constant

View File

@@ -188,7 +188,7 @@ void IrTypeClass::addBaseClassData(
ArrayIter<BaseClass> it2(*base->vtblInterfaces);
VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
Type* first = interfaces_idx->type->nextOf()->pointerTo();
Type* first = interfaces_idx->type->nextOf()->pointerTo();
// align offset
offset = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);