Exemple #1
0
void DtoResolveStruct(StructDeclaration* sd)
{
    // Make sure to resolve each struct type exactly once.
    if (sd->ir.resolved) return;
    sd->ir.resolved = true;

    Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars());
    LOG_SCOPE;

    // make sure type exists
    DtoType(sd->type);

    // if it's a forward declaration, all bets are off. The type should be enough
    if (sd->sizeok != 1)
        return;

    // create the IrStruct
    IrStruct* irstruct = new IrStruct(sd);
    sd->ir.irStruct = irstruct;

    // Set up our field metadata.
    for (ArrayIter<VarDeclaration> it(sd->fields); !it.done(); it.next())
    {
        VarDeclaration* vd = it.get();
        assert(!vd->ir.irField);
        (void)new IrField(vd);
    }

    // perform definition
    bool emitGlobalData = mustDefineSymbol(sd);
    if (emitGlobalData)
    {
        // emit the initZ symbol
        LLGlobalVariable* initZ = irstruct->getInitSymbol();

        // set initZ initializer
        initZ->setInitializer(irstruct->getDefaultInit());
    }

    // emit members
    if (sd->members)
    {
        for (ArrayIter<Dsymbol> it(sd->members); !it.done(); it.next())
        {
            it.get()->codegen(Type::sir);
        }
    }

    if (emitGlobalData)
    {
        // emit typeinfo
        DtoTypeInfoOf(sd->type);
    }
}
Exemple #2
0
void DtoResolveStruct(StructDeclaration* sd)
{
    // don't do anything if already been here
    if (sd->ir.resolved) return;
    // make sure above works :P
    sd->ir.resolved = true;

    // log what we're doing
    Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->loc.toChars());
    LOG_SCOPE;

    // make sure type exists
    DtoType(sd->type);

    // if it's a forward declaration, all bets are off. The type should be enough
    if (sd->sizeok != 1)
        return;

    // create the IrStruct
    IrStruct* irstruct = new IrStruct(sd);
    sd->ir.irStruct = irstruct;

    // make sure all fields really get their ir field
    ArrayIter<VarDeclaration> it(sd->fields);
    for (; !it.done(); it.next())
    {
        VarDeclaration* vd = it.get();
        if (vd->ir.irField == NULL) {
            new IrField(vd);
        } else {
            IF_LOG Logger::println("struct field already exists!!!");
        }
    }

    // perform definition
    bool needs_def = mustDefineSymbol(sd);
    if (needs_def)
    {
        // emit the initZ symbol
        LLGlobalVariable* initZ = irstruct->getInitSymbol();

        // set initZ initializer
        initZ->setInitializer(irstruct->getDefaultInit());
    }

    // emit members
    if (sd->members)
    {
        ArrayIter<Dsymbol> it(*sd->members);
        while (!it.done())
        {
            Dsymbol* member = it.get();
            if (member)
                member->codegen(Type::sir);
            it.next();
        }
    }

    if (needs_def)
    {
        // emit typeinfo
        DtoTypeInfoOf(sd->type);
    }
}
Exemple #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 );
}
Exemple #4
0
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd)
{
//     The layout is:
//        {
//         void **vptr;
//         monitor_t monitor;
//         byte[] initializer;     // static initialization data
//         char[] name;        // class name
//         void *[] vtbl;
//         Interface[] interfaces;
//         ClassInfo *base;        // base class
//         void *destructor;
//         void *invariant;        // class invariant
//         uint flags;
//         void *deallocator;
//         OffsetTypeInfo[] offTi;
//         void *defaultConstructor;
//         version(D_Version2)
//              immutable(void)* m_RTInfo;
//         else
//              TypeInfo typeinfo; // since dmd 1.045
//        }

    Logger::println("DtoDefineClassInfo(%s)", cd->toChars());
    LOG_SCOPE;

    assert(cd->type->ty == Tclass);
    TypeClass* cdty = static_cast<TypeClass*>(cd->type);

    IrStruct* ir = cd->ir.irStruct;
    assert(ir);

    ClassDeclaration* cinfo = ClassDeclaration::classinfo;

    if (cinfo->fields.dim != 12)
    {
        error("object.d ClassInfo class is incorrect");
        fatal();
    }

    // use the rtti builder
    RTTIBuilder b(ClassDeclaration::classinfo);

    LLConstant* c;

    LLType* voidPtr = getVoidPtrType();
    LLType* voidPtrPtr = getPtrToType(voidPtr);

    // byte[] init
    if (cd->isInterfaceDeclaration())
    {
        b.push_null_void_array();
    }
    else
    {
        LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType();
        size_t initsz = getTypePaddedSize(cd_type);
        b.push_void_array(initsz, ir->getInitSymbol());
    }

    // class name
    // code from dmd
    const char *name = cd->ident->toChars();
    size_t namelen = strlen(name);
    if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
    {
        name = cd->toPrettyChars();
        namelen = strlen(name);
    }
    b.push_string(name);

    // vtbl array
    if (cd->isInterfaceDeclaration())
    {
        b.push_array(0, getNullValue(voidPtrPtr));
    }
    else
    {
        c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr);
        b.push_array(cd->vtbl.dim, c);
    }

    // interfaces array
    b.push(ir->getClassInfoInterfaces());

    // base classinfo
    // interfaces never get a base , just the interfaces[]
    if (cd->baseClass && !cd->isInterfaceDeclaration())
        b.push_classinfo(cd->baseClass);
    else
        b.push_null(cinfo->type);

    // destructor
    if (cd->isInterfaceDeclaration())
        b.push_null_vp();
    else
        b.push(build_class_dtor(cd));

    // invariant
    VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]);
    b.push_funcptr(cd->inv, invVar->type);

    // uint flags
    unsigned flags;
    if (cd->isInterfaceDeclaration())
        flags = 4 | cd->isCOMinterface() | 32;
    else
        flags = build_classinfo_flags(cd);
    b.push_uint(flags);

    // deallocator
    b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo());

    // offset typeinfo
    VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]);

#if GENERATE_OFFTI

    if (cd->isInterfaceDeclaration())
        b.push_null(offTiVar->type);
    else
        b.push(build_offti_array(cd, DtoType(offTiVar->type)));

#else // GENERATE_OFFTI

    b.push_null(offTiVar->type);

#endif // GENERATE_OFFTI

    // default constructor
    VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]);
    b.push_funcptr(cd->defaultCtor, defConstructorVar->type);

#if DMDV2
    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (cd->getRTInfo)
        b.push(cd->getRTInfo->toConstElem(gIR));
    else if (flags & 2)
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers
#else
    // typeinfo - since 1.045
    b.push_typeinfo(cd->type);
#endif

    /*size_t n = inits.size();
    for (size_t i=0; i<n; ++i)
    {
        Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n';
    }*/

    // build the initializer
    LLType *initType = ir->classInfo->getType()->getContainedType(0);
    LLConstant* finalinit = b.get_constant(isaStruct(initType));

    //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
    ir->constClassInfo = finalinit;

    // sanity check
    assert(finalinit->getType() == initType &&
        "__ClassZ initializer does not match the ClassInfo type");

    // return initializer
    return finalinit;
}
Exemple #5
0
void DtoResolveClass(ClassDeclaration* cd)
{
    // make sure the base classes are processed first
    ArrayIter<BaseClass> base_iter(cd->baseclasses);
    while (base_iter.more())
    {
        BaseClass* bc = base_iter.get();
        if (bc)
        {
            bc->base->codegen(Type::sir);
        }
        base_iter.next();
    }

    if (cd->ir.resolved) return;
    cd->ir.resolved = true;

    Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
    LOG_SCOPE;

    // make sure type exists
    DtoType(cd->type);

    // create IrStruct
    assert(cd->ir.irStruct == NULL);
    IrStruct* irstruct = new IrStruct(cd);
    cd->ir.irStruct = irstruct;

    // make sure all fields really get their ir field
    ArrayIter<VarDeclaration> it(cd->fields);
    for (; !it.done(); it.next())
    {
        VarDeclaration* vd = it.get();
        if (vd->ir.irField == NULL) {
            new IrField(vd);
        } else {
            IF_LOG Logger::println("class field already exists!!!");
        }
    }

    bool needs_def = mustDefineSymbol(cd);

    // emit the ClassZ symbol
    LLGlobalVariable* ClassZ = irstruct->getClassInfoSymbol();

    // emit the interfaceInfosZ symbol if necessary
    if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0)
        irstruct->getInterfaceArraySymbol(); // initializer is applied when it's built

    // interface only emit typeinfo and classinfo
    if (cd->isInterfaceDeclaration())
    {
        irstruct->initializeInterface();
    }
    else
    {
        // emit the initZ symbol
        LLGlobalVariable* initZ = irstruct->getInitSymbol();
        // emit the vtblZ symbol
        LLGlobalVariable* vtblZ = irstruct->getVtblSymbol();

        // perform definition
        if (needs_def)
        {
            // set symbol initializers
            initZ->setInitializer(irstruct->getDefaultInit());
            vtblZ->setInitializer(irstruct->getVtblInit());
        }
    }

    // emit members
    if (cd->members)
    {
        ArrayIter<Dsymbol> it(*cd->members);
        while (!it.done())
        {
            Dsymbol* member = it.get();
            if (member)
                member->codegen(Type::sir);
            it.next();
        }
    }

    if (needs_def)
    {
        // emit typeinfo
        DtoTypeInfoOf(cd->type);

        // define classinfo
        ClassZ->setInitializer(irstruct->getClassInfoInit());
    }
}
Exemple #6
0
void TypeInfoStructDeclaration::llvmDefine()
{
    Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // make sure struct is resolved
    assert(tinfo->ty == Tstruct);
    TypeStruct *tc = static_cast<TypeStruct *>(tinfo);
    StructDeclaration *sd = tc->sym;

    // can't emit typeinfo for forward declarations
    if (sd->sizeok != 1)
    {
        sd->error("cannot emit TypeInfo for forward declaration");
        fatal();
    }

    sd->codegen(Type::sir);
    IrStruct* irstruct = sd->ir.irStruct;

    RTTIBuilder b(Type::typeinfostruct);

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // never emit a null array, even for zero initialized typeinfo
    // the size() method uses this array!
    size_t init_size = getTypeStoreSize(tc->irtype->getType());
    b.push_void_array(init_size, irstruct->getInitSymbol());

    // toX functions ground work
    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;
        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
#if DMDV2
        tftohash ->mod = MODconst;
#endif
        tftohash = static_cast<TypeFunction *>(tftohash->semantic(0, &sc));

#if DMDV2
        Type *retType = Type::tchar->invariantOf()->arrayOf();
#else
        Type *retType = Type::tchar->arrayOf();
#endif
        tftostring = new TypeFunction(NULL, retType, 0, LINKd);
        tftostring = static_cast<TypeFunction *>(tftostring->semantic(0, &sc));
    }

    // this one takes a parameter, so we need to build a new one each time
    // to get the right type. can we avoid this?
    TypeFunction *tfcmpptr;
    {
        Scope sc;
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif
        arguments->push(arg);
        tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
#if DMDV2
        tfcmpptr->mod = MODconst;
#endif
        tfcmpptr = static_cast<TypeFunction *>(tfcmpptr->semantic(0, &sc));
    }

    // well use this module for all overload lookups
    Module *gm = getModule();

    // toHash
    FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm);
    b.push_funcptr(fd);

    // opEquals
#if DMDV2
    fd = sd->xeq;
#else
    fd = find_method_overload(sd, Id::eq, tfcmpptr, gm);
#endif
    b.push_funcptr(fd);

    // opCmp
    fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm);
    b.push_funcptr(fd);

    // toString
    fd = find_method_overload(sd, Id::tostring, tftostring, gm);
    b.push_funcptr(fd);

    // uint m_flags;
    unsigned hasptrs = tc->hasPointers() ? 1 : 0;
    b.push_uint(hasptrs);

#if DMDV2

    ClassDeclaration* tscd = Type::typeinfostruct;

    assert((!global.params.is64bit && tscd->fields.dim == 11) ||
           (global.params.is64bit && tscd->fields.dim == 13));

    //void function(void*)                    xdtor;
    b.push_funcptr(sd->dtor);

    //void function(void*)                    xpostblit;
    FuncDeclaration *xpostblit = sd->postblit;
    if (xpostblit && sd->postblit->storage_class & STCdisable)
        xpostblit = 0;
    b.push_funcptr(xpostblit);

    //uint m_align;
    b.push_uint(tc->alignsize());

    if (global.params.is64bit)
    {
        // TypeInfo m_arg1;
        // TypeInfo m_arg2;
        TypeTuple *tup = tc->toArgTypes();
        assert(tup->arguments->dim <= 2);
        for (unsigned i = 0; i < 2; i++)
        {
            if (i < tup->arguments->dim)
            {
                Type *targ = static_cast<Parameter *>(tup->arguments->data[i])->type;
                targ = targ->merge();
                b.push_typeinfo(targ);
            }
            else
                b.push_null(Type::typeinfo->type);
        }
    }

    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (sd->getRTInfo)
        b.push(sd->getRTInfo->toConstElem(gIR));
    else if (!tc->hasPointers())
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers

#endif

    // finish
    b.finalize(ir.irGlobal);
}