Пример #1
0
void IrTypeClass::addBaseClassData(
    std::vector<llvm::Type *> & defaultTypes,
    ClassDeclaration * base,
    size_t & offset,
    size_t & field_index)
{
    if (base->baseClass)
    {
        addBaseClassData(defaultTypes, base->baseClass, offset, field_index);
    }

    // FIXME: merge code with structs in IrTypeAggr

    // mirror the sd->fields array but only fill in contributors
    size_t n = base->fields.dim;
    LLSmallVector<VarDeclaration*, 16> data(n, NULL);
    default_fields.reserve(n);

    // first fill in the fields with explicit initializers
    VarDeclarationIter field_it(base->fields);
    for (; field_it.more(); field_it.next())
    {
        // init is !null for explicit inits
        if (field_it->init != NULL)
        {
            IF_LOG Logger::println("adding explicit initializer for struct field %s",
                field_it->toChars());

            data[field_it.index] = *field_it;

            size_t f_begin = field_it->offset;
            size_t f_end = f_begin + field_it->type->size();

            // make sure there is no overlap
            for (size_t i = 0; i < field_it.index; i++)
            {
                if (data[i] != NULL)
                {
                    VarDeclaration* vd = data[i];
                    size_t v_begin = vd->offset;
                    size_t v_end = v_begin + vd->type->size();

                    if (v_begin >= f_end || v_end <= f_begin)
                        continue;

                    base->error(vd->loc, "has overlapping initialization for %s and %s",
                        field_it->toChars(), vd->toChars());
                }
            }
        }
    }

    if (global.errors)
    {
        fatal();
    }

    // fill in default initializers
    field_it = VarDeclarationIter(base->fields);
    for (;field_it.more(); field_it.next())
    {
        if (data[field_it.index])
            continue;

        size_t f_begin = field_it->offset;
        size_t f_end = f_begin + field_it->type->size();

        // make sure it doesn't overlap anything explicit
        bool overlaps = false;
        for (size_t i = 0; i < n; i++)
        {
            if (data[i])
            {
                size_t v_begin = data[i]->offset;
                size_t v_end = v_begin + data[i]->type->size();

                if (v_begin >= f_end || v_end <= f_begin)
                    continue;

                overlaps = true;
                break;
            }
        }

        // if no overlap was found, add the default initializer
        if (!overlaps)
        {
            IF_LOG Logger::println("adding default initializer for struct field %s",
                field_it->toChars());
            data[field_it.index] = *field_it;
        }
    }

    // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary.

    // first we sort the list by offset
    std::sort(data.begin(), data.end(), var_offset_sort_cb);

    // add types to list
    for (size_t i = 0; i < n; i++)
    {
        VarDeclaration* vd = data[i];

        if (vd == NULL)
            continue;

        assert(vd->offset >= offset && "it's a bug... most likely DMD bug 2481");

        // add to default field list
        if (cd == base)
            default_fields.push_back(vd);

        // get next aligned offset for this type
        size_t alignedoffset = realignOffset(offset, vd->type);

        // insert explicit padding?
        if (alignedoffset < vd->offset)
        {
            field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
        }

        // add default type
        defaultTypes.push_back(DtoType(vd->type));

        // advance offset to right past this field
        offset = vd->offset + vd->type->size();

        // create ir field
        vd->aggrIndex = (unsigned)field_index;
        ++field_index;
    }

    // any interface implementations?
    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
    {
        bool new_instances = (base == cd);

        ArrayIter<BaseClass> it2(*base->vtblInterfaces);

        VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
	Type* first = interfaces_idx->type->nextOf()->pointerTo();

        // align offset
        offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1);

        for (; !it2.done(); it2.next())
        {
            BaseClass* b = it2.get();
            IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars());

            FuncDeclarations arr;
            b->fillVtbl(cd, &arr, new_instances);

            llvm::Type* ivtbl_type = llvm::StructType::get(gIR->context(), buildVtblType(first, &arr));
            defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0));

            offset += PTRSIZE;

            // add to the interface map
            addInterfaceToMap(b->base, field_index);
            field_index++;

            // inc count
            num_interface_vtbls++;
        }
    }

#if 0
    // tail padding?
    if (offset < base->structsize)
    {
        field_index += add_zeros(defaultTypes, base->structsize - offset);
        offset = base->structsize;
    }
#endif
}
Пример #2
0
llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index)
{
    ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base);
    if (it != interfaceVtblMap.end())
        return it->second;

    IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
        b->base->toPrettyChars(), aggrdecl->toPrettyChars());
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd && "not a class aggregate");

    FuncDeclarations vtbl_array;
    b->fillVtbl(cd, &vtbl_array, new_instance);

    std::vector<llvm::Constant*> constants;
    constants.reserve(vtbl_array.dim);

    // 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)
    };

    llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
        getInterfaceArraySymbol(), idxs, true);

    constants.push_back(c);

    // add virtual function pointers
    size_t n = vtbl_array.dim;
    for (size_t i = 1; i < n; i++)
    {
        Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]);
        if (dsym == NULL)
        {
            // FIXME
            // why is this null?
            // happens for mini/s.d
            constants.push_back(getNullValue(getVoidPtrType()));
            continue;
        }

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "vtbl entry not a function");

        assert((!fd->isAbstract() || fd->fbody) &&
            "null symbol in interface implementation vtable");

        fd->codegen(Type::sir);
        assert(fd->ir.irFunc && "invalid vtbl function");

        constants.push_back(fd->ir.irFunc->func);
    }

    // build the vtbl constant
    llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false);

    // create the global variable to hold it
    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);

    std::string mangle("_D");
    mangle.append(cd->mangle());
    mangle.append("11__interface");
    mangle.append(b->base->mangle());
    mangle.append("6__vtblZ");

    llvm::GlobalVariable* GV = new llvm::GlobalVariable(
        *gIR->module,
        vtbl_constant->getType(),
        true,
        _linkage,
        vtbl_constant,
        mangle
    );

    // insert into the vtbl map
    interfaceVtblMap.insert(std::make_pair(b->base, GV));

    return GV;
}
Пример #3
0
LLConstant * IrStruct::getClassInfoInterfaces()
{
    IF_LOG Logger::println("Building ClassInfo.interfaces");
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd);

    size_t n = interfacesWithVtbls.size();
    assert(stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls() == n &&
        "inconsistent number of interface vtables in this class");

    VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);

    if (n == 0)
        return getNullValue(DtoType(interfaces_idx->type));

// Build array of:
//
//     struct Interface
//     {
//         ClassInfo   classinfo;
//         void*[]     vtbl;
//         ptrdiff_t   offset;
//     }

    LLSmallVector<LLConstant*, 6> constants;
    constants.reserve(cd->vtblInterfaces->dim);

    LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type);
    LLType* voidptrptr_type = DtoType(
        Type::tvoid->pointerTo()->pointerTo());
    VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
    LLStructType* interface_type = isaStruct(DtoType(idx->type->nextOf()));
    assert(interface_type);

    for (size_t i = 0; i < n; ++i)
    {
        BaseClass* it = interfacesWithVtbls[i];

        IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars());

        IrStruct* irinter = it->base->ir.irStruct;
        assert(irinter && "interface has null IrStruct");
        IrTypeClass* itc = stripModifiers(irinter->type)->irtype->isClass();
        assert(itc && "null interface IrTypeClass");

        // classinfo
        LLConstant* ci = irinter->getClassInfoSymbol();
        ci = DtoBitCast(ci, classinfo_type);

        // vtbl
        LLConstant* vtb;
        // interface get a null
        if (cd->isInterfaceDeclaration())
        {
            vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type));
        }
        else
        {
            ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base);
            assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
            vtb = itv->second;
            vtb = DtoBitCast(vtb, voidptrptr_type);
            vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
        }

        // offset
        LLConstant* off = DtoConstSize_t(it->offset);

        // create Interface struct
        LLConstant* inits[3] = { ci, vtb, off };
        LLConstant* entry = LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3));
        constants.push_back(entry);
    }

    // create Interface[N]
    LLArrayType* array_type = llvm::ArrayType::get(interface_type, n);

    // create and apply initializer
    LLConstant* arr = LLConstantArray::get(array_type, constants);
    classInterfacesArray->setInitializer(arr);

    // return null, only baseclass provide interfaces
    if (cd->vtblInterfaces->dim == 0)
    {
        return getNullValue(DtoType(interfaces_idx->type));
    }

    // only the interface explicitly implemented by this class
    // (not super classes) should show in ClassInfo
    LLConstant* idxs[2] = {
        DtoConstSize_t(0),
        DtoConstSize_t(n - cd->vtblInterfaces->dim)
    };

    LLConstant* ptr = llvm::ConstantExpr::getGetElementPtr(
        classInterfacesArray, idxs, true);

    // return as a slice
    return DtoConstSlice( DtoConstSize_t(cd->vtblInterfaces->dim), ptr );
}
Пример #4
0
llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index)
{
    ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base);
    if (it != interfaceVtblMap.end())
        return it->second;

    IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
        b->base->toPrettyChars(), aggrdecl->toPrettyChars());
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd && "not a class aggregate");

    FuncDeclarations vtbl_array;
    b->fillVtbl(cd, &vtbl_array, new_instance);

    std::vector<llvm::Constant*> constants;
    constants.reserve(vtbl_array.dim);

    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)
        };

        llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
            getInterfaceArraySymbol(), idxs, true);

        constants.push_back(c);
    }

    // add virtual function pointers
    size_t n = vtbl_array.dim;
    for (size_t i = b->base->vtblOffset(); i < n; i++)
    {
        Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]);
        if (dsym == NULL)
        {
            // FIXME
            // why is this null?
            // happens for mini/s.d
            constants.push_back(getNullValue(getVoidPtrType()));
            continue;
        }

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "vtbl entry not a function");

        assert((!fd->isAbstract() || fd->fbody) &&
            "null symbol in interface implementation vtable");

        fd->codegen(Type::sir);
        assert(fd->ir.irFunc && "invalid vtbl function");

        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
    llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false);

    // create the global variable to hold it
    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);

    std::string mangle("_D");
    mangle.append(cd->mangle());
    mangle.append("11__interface");
    mangle.append(b->base->mangle());
    mangle.append("6__vtblZ");

    llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc,
        *gIR->module,
        vtbl_constant->getType(),
        true,
        _linkage,
        vtbl_constant,
        mangle
    );

    // insert into the vtbl map
    interfaceVtblMap.insert(std::make_pair(b->base, GV));

    return GV;
}