예제 #1
0
파일: toctype.c 프로젝트: CyberShadow/dmd
    void visit(TypeFunction *t)
    {
        size_t nparams = Parameter::dim(t->parameters);

        type *tmp[10];
        type **ptypes = tmp;
        if (nparams > 10)
            ptypes = (type **)malloc(sizeof(type*) * nparams);

        for (size_t i = 0; i < nparams; i++)
        {
            Parameter *p = Parameter::getNth(t->parameters, i);
            type *tp = Type_toCtype(p->type);
            if (p->storageClass & (STCout | STCref))
                tp = type_allocn(TYref, tp);
            else if (p->storageClass & STClazy)
            {
                // Mangle as delegate
                type *tf = type_function(TYnfunc, NULL, 0, false, tp);
                tp = type_delegate(tf);
            }
            ptypes[i] = tp;
        }

        t->ctype = type_function(totym(t), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next));

        if (nparams > 10)
            free(ptypes);
    }
예제 #2
0
파일: toctype.c 프로젝트: rwtsoftware/dmd
    void visit(TypeEnum *t)
    {
        //printf("TypeEnum::toCtype() '%s'\n", t->sym->toChars());
        Type *tm = t->mutableOf();
        if (tm->ctype && tybasic(tm->ctype->Tty) == TYenum)
        {
            Symbol *s = tm->ctype->Ttag;
            assert(s);
            t->ctype = type_alloc(TYenum);
            t->ctype->Ttag = (Classsym *)s;            // enum tag name
            t->ctype->Tcount++;
            t->ctype->Tnext = tm->ctype->Tnext;
            t->ctype->Tnext->Tcount++;
            // Add modifiers
            switch (t->mod)
            {
                case 0:
                    assert(0);
                    break;
                case MODconst:
                case MODwild:
                case MODwildconst:
                    t->ctype->Tty |= mTYconst;
                    break;
                case MODshared:
                    t->ctype->Tty |= mTYshared;
                    break;
                case MODshared | MODconst:
                case MODshared | MODwild:
                case MODshared | MODwildconst:
                    t->ctype->Tty |= mTYshared | mTYconst;
                    break;
                case MODimmutable:
                    t->ctype->Tty |= mTYimmutable;
                    break;
                default:
                    assert(0);
            }
        }
        else if (!t->sym->memtype)
        {
            // Bugzilla 13792
            t->ctype = Type_toCtype(Type::tvoid);
        }
        else if (t->sym->memtype->toBasetype()->ty == Tint32)
        {
            t->ctype = type_enum(t->sym->toPrettyChars(true), Type_toCtype(t->sym->memtype));
            tm->ctype = t->ctype;
        }
        else
        {
            t->ctype = Type_toCtype(t->sym->memtype);
        }

        //printf("t = %p, Tflags = x%x\n", t, t->Tflags);
    }
예제 #3
0
파일: toctype.c 프로젝트: JenkinsDev/dmd
    void visit(TypeFunction *t)
    {
        size_t nparams = Parameter::dim(t->parameters);

        type *tmp[10];
        type **ptypes = tmp;
        if (nparams > 10)
            ptypes = (type **)malloc(sizeof(type*) * nparams);

        for (size_t i = 0; i < nparams; i++)
        {
            Parameter *arg = Parameter::getNth(t->parameters, i);
            type *tp = Type_toCtype(arg->type);
            if (arg->storageClass & (STCout | STCref))
                tp = type_allocn(TYref, tp);
            ptypes[i] = tp;
        }

        t->ctype = type_function(t->totym(), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next));

        if (nparams > 10)
            free(ptypes);
    }
예제 #4
0
파일: tocsym.c 프로젝트: Arpit007/dmd
Symbol *aaGetSymbol(TypeAArray *taa, const char *func, int flags)
{
#ifdef DEBUG
        assert((flags & ~1) == 0);
#endif

        // Dumb linear symbol table - should use associative array!
        static Symbols *sarray = NULL;

        //printf("aaGetSymbol(func = '%s', flags = %d, key = %p)\n", func, flags, key);
        char *id = (char *)alloca(3 + strlen(func) + 1);
        sprintf(id, "_aa%s", func);
        if (!sarray)
            sarray = Symbols_create();

        // See if symbol is already in sarray
        for (size_t i = 0; i < sarray->dim; i++)
        {
            Symbol *s = (*sarray)[i];
            if (strcmp(id, s->Sident) == 0)
            {
#ifdef DEBUG
                assert(s);
#endif
                return s;                       // use existing Symbol
            }
        }

        // Create new Symbol

        Symbol *s = symbol_calloc(id);
        slist_add(s);
        s->Sclass = SCextern;
        s->Ssymnum = -1;
        symbol_func(s);

        type *t = type_function(TYnfunc, NULL, 0, false, Type_toCtype(taa->next));
        t->Tmangle = mTYman_c;
        s->Stype = t;

        sarray->push(s);                        // remember it
        return s;
}
예제 #5
0
파일: toctype.c 프로젝트: CyberShadow/dmd
    void visit(TypeClass *t)
    {
        //printf("TypeClass::toCtype() %s\n", toChars());
        type *tc = type_struct_class(t->sym->toPrettyChars(true), t->sym->alignsize, t->sym->structsize,
                NULL,
                NULL,
                false,
                true,
                true);

        t->ctype = type_pointer(tc);

        /* Add in fields of the class
         * (after setting ctype to avoid infinite recursion)
         */
        if (global.params.symdebug)
        {
            for (size_t i = 0; i < t->sym->fields.dim; i++)
            {
                VarDeclaration *v = t->sym->fields[i];
                symbol_struct_addField(tc->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset);
            }
        }
    }
예제 #6
0
파일: glue.c 프로젝트: AlexBezzubenko/dmd
void FuncDeclaration_toObjFile(FuncDeclaration *fd, bool multiobj)
{
    ClassDeclaration *cd = fd->parent->isClassDeclaration();
    //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", fd, fd->parent->toChars(), fd->toChars());

    //if (type) printf("type = %s\n", type->toChars());
#if 0
    //printf("line = %d\n", getWhere() / LINEINC);
    EEcontext *ee = env->getEEcontext();
    if (ee->EEcompile == 2)
    {
        if (ee->EElinnum < (getWhere() / LINEINC) ||
            ee->EElinnum > (endwhere / LINEINC)
           )
            return;             // don't compile this function
        ee->EEfunc = toSymbol(this);
    }
#endif

    if (fd->semanticRun >= PASSobj) // if toObjFile() already run
        return;

    if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next == NULL)
        return;

    // If errors occurred compiling it, such as bugzilla 6118
    if (fd->type && fd->type->ty == Tfunction && ((TypeFunction *)fd->type)->next->ty == Terror)
        return;

    if (global.errors)
        return;

    if (!fd->fbody)
        return;

    UnitTestDeclaration *ud = fd->isUnitTestDeclaration();
    if (ud && !global.params.useUnitTests)
        return;

    if (multiobj && !fd->isStaticDtorDeclaration() && !fd->isStaticCtorDeclaration())
    {
        obj_append(fd);
        return;
    }

    if (fd->semanticRun == PASSsemanticdone)
    {
        /* What happened is this function failed semantic3() with errors,
         * but the errors were gagged.
         * Try to reproduce those errors, and then fail.
         */
        fd->error("errors compiling the function");
        return;
    }
    assert(fd->semanticRun == PASSsemantic3done);
    assert(fd->ident != Id::empty);

    for (FuncDeclaration *fd2 = fd; fd2; )
    {
        if (fd2->inNonRoot())
            return;
        if (fd2->isNested())
            fd2 = fd2->toParent2()->isFuncDeclaration();
        else
            break;
    }

    FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration();
    if (fd->isNested())
    {
        if (fdp && fdp->semanticRun < PASSobj)
        {
            if (fdp->semantic3Errors)
                return;

            /* Can't do unittest's out of order, they are order dependent in that their
             * execution is done in lexical order.
             */
            if (UnitTestDeclaration *udp = fdp->isUnitTestDeclaration())
            {
                udp->deferredNested.push(fd);
                return;
            }
        }
    }

    if (fd->isArrayOp && isDruntimeArrayOp(fd->ident))
    {
        // Implementation is in druntime
        return;
    }

    // start code generation
    fd->semanticRun = PASSobj;

    if (global.params.verbose)
        fprintf(global.stdmsg, "function  %s\n", fd->toPrettyChars());

    Symbol *s = toSymbol(fd);
    func_t *f = s->Sfunc;

    // tunnel type of "this" to debug info generation
    if (AggregateDeclaration* ad = fd->parent->isAggregateDeclaration())
    {
        ::type* t = Type_toCtype(ad->getType());
        if (cd)
            t = t->Tnext; // skip reference
        f->Fclass = (Classsym *)t;
    }

#if TARGET_WINDOS
    /* This is done so that the 'this' pointer on the stack is the same
     * distance away from the function parameters, so that an overriding
     * function can call the nested fdensure or fdrequire of its overridden function
     * and the stack offsets are the same.
     */
    if (fd->isVirtual() && (fd->fensure || fd->frequire))
        f->Fflags3 |= Ffakeeh;
#endif

#if TARGET_OSX
    s->Sclass = SCcomdat;
#else
    s->Sclass = SCglobal;
#endif
    for (Dsymbol *p = fd->parent; p; p = p->parent)
    {
        if (p->isTemplateInstance())
        {
            s->Sclass = SCcomdat;
            break;
        }
    }

    /* Vector operations should be comdat's
     */
    if (fd->isArrayOp)
        s->Sclass = SCcomdat;

    if (fd->isNested())
    {
        //if (!(config.flags3 & CFG3pic))
        //    s->Sclass = SCstatic;
        f->Fflags3 |= Fnested;

        /* The enclosing function must have its code generated first,
         * in order to calculate correct frame pointer offset.
         */
        if (fdp && fdp->semanticRun < PASSobj)
        {
            toObjFile(fdp, multiobj);
        }
    }
    else
    {
        const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;

        // Pull in RTL startup code (but only once)
        if (fd->isMain() && onlyOneMain(fd->loc))
        {
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
            objmod->external_def("_main");
            objmod->ehsections();   // initialize exception handling sections
#endif
#if TARGET_WINDOS
            if (global.params.mscoff)
            {
                objmod->external_def("main");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("_main");
                objmod->external_def("__acrtused_con");
            }
#endif
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
        else if (strcmp(s->Sident, "main") == 0 && fd->linkage == LINKc)
        {
#if TARGET_WINDOS
            if (global.params.mscoff)
            {
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
            }
            else
            {
                objmod->external_def("__acrtused_con");        // bring in C startup code
                objmod->includelib("snn.lib");          // bring in C runtime library
            }
#endif
            s->Sclass = SCglobal;
        }
#if TARGET_WINDOS
        else if (fd->isWinMain() && onlyOneMain(fd->loc))
        {
            if (global.params.mscoff)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }

        // Pull in RTL startup code
        else if (fd->isDllMain() && onlyOneMain(fd->loc))
        {
            if (global.params.mscoff)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused_dll");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
#endif
    }

    symtab_t *symtabsave = cstate.CSpsymtab;
    cstate.CSpsymtab = &f->Flocsym;

    // Find module m for this function
    Module *m = NULL;
    for (Dsymbol *p = fd->parent; p; p = p->parent)
    {
        m = p->isModule();
        if (m)
            break;
    }

    IRState irs(m, fd);
    Dsymbols deferToObj;                   // write these to OBJ file later
    irs.deferToObj = &deferToObj;

    symbol *shidden = NULL;
    Symbol *sthis = NULL;
    tym_t tyf = tybasic(s->Stype->Tty);
    //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
    int reverse = tyrevfunc(s->Stype->Tty);

    assert(fd->type->ty == Tfunction);
    TypeFunction *tf = (TypeFunction *)fd->type;
    RET retmethod = retStyle(tf);
    if (retmethod == RETstack)
    {
        // If function returns a struct, put a pointer to that
        // as the first argument
        ::type *thidden = Type_toCtype(tf->next->pointerTo());
        char hiddenparam[5+4+1];
        static int hiddenparami;    // how many we've generated so far

        sprintf(hiddenparam,"__HID%d",++hiddenparami);
        shidden = symbol_name(hiddenparam,SCparameter,thidden);
        shidden->Sflags |= SFLtrue | SFLfree;
        if (fd->nrvo_can && fd->nrvo_var && fd->nrvo_var->nestedrefs.dim)
            type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile);
        irs.shidden = shidden;
        fd->shidden = shidden;
    }
    else
    {
        // Register return style cannot make nrvo.
        // Auto functions keep the nrvo_can flag up to here,
        // so we should eliminate it before entering backend.
        fd->nrvo_can = 0;
    }

    if (fd->vthis)
    {
        assert(!fd->vthis->csym);
        sthis = toSymbol(fd->vthis);
        irs.sthis = sthis;
        if (!(f->Fflags3 & Fnested))
            f->Fflags3 |= Fmember;
    }

    // Estimate number of parameters, pi
    size_t pi = (fd->v_arguments != NULL);
    if (fd->parameters)
        pi += fd->parameters->dim;

    // Create a temporary buffer, params[], to hold function parameters
    Symbol *paramsbuf[10];
    Symbol **params = paramsbuf;    // allocate on stack if possible
    if (pi + 2 > 10)                // allow extra 2 for sthis and shidden
    {
        params = (Symbol **)malloc((pi + 2) * sizeof(Symbol *));
        assert(params);
    }

    // Get the actual number of parameters, pi, and fill in the params[]
    pi = 0;
    if (fd->v_arguments)
    {
        params[pi] = toSymbol(fd->v_arguments);
        pi += 1;
    }
    if (fd->parameters)
    {
        for (size_t i = 0; i < fd->parameters->dim; i++)
        {
            VarDeclaration *v = (*fd->parameters)[i];
            //printf("param[%d] = %p, %s\n", i, v, v->toChars());
            assert(!v->csym);
            params[pi + i] = toSymbol(v);
        }
        pi += fd->parameters->dim;
    }

    if (reverse)
    {
        // Reverse params[] entries
        for (size_t i = 0; i < pi/2; i++)
        {
            Symbol *sptmp = params[i];
            params[i] = params[pi - 1 - i];
            params[pi - 1 - i] = sptmp;
        }
    }

    if (shidden)
    {
#if 0
        // shidden becomes last parameter
        params[pi] = shidden;
#else
        // shidden becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = shidden;
#endif
        pi++;
    }


    if (sthis)
    {
#if 0
        // sthis becomes last parameter
        params[pi] = sthis;
#else
        // sthis becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = sthis;
#endif
        pi++;
    }

    if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
         fd->linkage != LINKd && shidden && sthis)
    {
        /* swap shidden and sthis
         */
        Symbol *sp = params[0];
        params[0] = params[1];
        params[1] = sp;
    }

    for (size_t i = 0; i < pi; i++)
    {
        Symbol *sp = params[i];
        sp->Sclass = SCparameter;
        sp->Sflags &= ~SFLspill;
        sp->Sfl = FLpara;
        symbol_add(sp);
    }

    // Determine register assignments
    if (pi)
    {
        FuncParamRegs fpr(tyf);

        for (size_t i = 0; i < pi; i++)
        {
            Symbol *sp = params[i];
            if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2))
            {
                sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar;
                sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast;
            }
        }
    }

    // Done with params
    if (params != paramsbuf)
        free(params);
    params = NULL;

    if (fd->fbody)
    {
        localgot = NULL;

        Statement *sbody = fd->fbody;

        Blockx bx;
        memset(&bx,0,sizeof(bx));
        bx.startblock = block_calloc();
        bx.curblock = bx.startblock;
        bx.funcsym = s;
        bx.scope_index = -1;
        bx.classdec = cd;
        bx.member = fd;
        bx.module = fd->getModule();
        irs.blx = &bx;

        /* Doing this in semantic3() caused all kinds of problems:
         * 1. couldn't reliably get the final mangling of the function name due to fwd refs
         * 2. impact on function inlining
         * 3. what to do when writing out .di files, or other pretty printing
         */
        if (global.params.trace && !fd->isCMain())
        {
            /* The profiler requires TLS, and TLS may not be set up yet when C main()
             * gets control (i.e. OSX), leading to a crash.
             */
            /* Wrap the entire function body in:
             *   trace_pro("funcname");
             *   try
             *     body;
             *   finally
             *     _c_trace_epi();
             */
            StringExp *se = StringExp::create(Loc(), s->Sident);
            se->type = Type::tstring;
            se->type = se->type->semantic(Loc(), NULL);
            Expressions *exps = Expressions_create();
            exps->push(se);
            FuncDeclaration *fdpro = FuncDeclaration::genCfunc(NULL, Type::tvoid, "trace_pro");
            Expression *ec = VarExp::create(Loc(), fdpro);
            Expression *e = CallExp::create(Loc(), ec, exps);
            e->type = Type::tvoid;
            Statement *sp = ExpStatement::create(fd->loc, e);

            FuncDeclaration *fdepi = FuncDeclaration::genCfunc(NULL, Type::tvoid, "_c_trace_epi");
            ec = VarExp::create(Loc(), fdepi);
            e = CallExp::create(Loc(), ec);
            e->type = Type::tvoid;
            Statement *sf = ExpStatement::create(fd->loc, e);

            Statement *stf;
            if (sbody->blockExit(fd, false) == BEfallthru)
                stf = CompoundStatement::create(Loc(), sbody, sf);
            else
                stf = TryFinallyStatement::create(Loc(), sbody, sf);
            sbody = CompoundStatement::create(Loc(), sp, stf);
        }

        buildClosure(fd, &irs);

#if TARGET_WINDOS
        if (fd->isSynchronized() && cd && config.flags2 & CFG2seh &&
            !fd->isStatic() && !sbody->usesEH() && !global.params.trace)
        {
            /* The "jmonitor" hack uses an optimized exception handling frame
             * which is a little shorter than the more general EH frame.
             */
            s->Sfunc->Fflags3 |= Fjmonitor;
        }
#endif

        Statement_toIR(sbody, &irs);
        bx.curblock->BC = BCret;

        f->Fstartblock = bx.startblock;
//      einit = el_combine(einit,bx.init);

        if (fd->isCtorDeclaration())
        {
            assert(sthis);
            for (block *b = f->Fstartblock; b; b = b->Bnext)
            {
                if (b->BC == BCret)
                {
                    b->BC = BCretexp;
                    b->Belem = el_combine(b->Belem, el_var(sthis));
                }
            }
        }
    }

    // If static constructor
    if (fd->isSharedStaticCtorDeclaration())        // must come first because it derives from StaticCtorDeclaration
    {
        ssharedctors.push(s);
    }
    else if (fd->isStaticCtorDeclaration())
    {
        sctors.push(s);
    }

    // If static destructor
    if (fd->isSharedStaticDtorDeclaration())        // must come first because it derives from StaticDtorDeclaration
    {
        SharedStaticDtorDeclaration *f = fd->isSharedStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {
            /* Increment destructor's vgate at construction time
             */
            esharedctorgates.push(f);
        }

        sshareddtors.shift(s);
    }
    else if (fd->isStaticDtorDeclaration())
    {
        StaticDtorDeclaration *f = fd->isStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {
            /* Increment destructor's vgate at construction time
             */
            ectorgates.push(f);
        }

        sdtors.shift(s);
    }

    // If unit test
    if (ud)
    {
        stests.push(s);
    }

    if (global.errors)
    {
        // Restore symbol table
        cstate.CSpsymtab = symtabsave;
        return;
    }

    writefunc(s);
    // Restore symbol table
    cstate.CSpsymtab = symtabsave;

    if (fd->isExport())
        objmod->export_symbol(s, Para.offset);

    for (size_t i = 0; i < irs.deferToObj->dim; i++)
    {
        Dsymbol *s = (*irs.deferToObj)[i];
        toObjFile(s, false);
    }

    if (ud)
    {
        for (size_t i = 0; i < ud->deferredNested.dim; i++)
        {
            FuncDeclaration *fd = ud->deferredNested[i];
            toObjFile(fd, false);
        }
    }

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
    // A hack to get a pointer to this function put in the .dtors segment
    if (fd->ident && memcmp(fd->ident->toChars(), "_STD", 4) == 0)
        objmod->staticdtor(s);
#endif
    if (irs.startaddress)
    {
        //printf("Setting start address\n");
        objmod->startaddress(irs.startaddress);
    }
}
예제 #7
0
파일: tocvdebug.c 프로젝트: dacki/dmd
        void visit(VarDeclaration *vd)
        {
            //printf("VarDeclaration::cvMember(p = %p) '%s'\n", p, vd->toChars());

            if (vd->type->toBasetype()->ty == Ttuple)
                return;

            char *id = vd->toChars();

            if (!p)
            {
                if (vd->isField())
                {
                    if (config.fulltypes == CV8)
                        result += 2;
                    result += 6 + cv_stringbytes(id);
                    result += cv4_numericbytes(vd->offset);
                }
                else if (vd->isStatic())
                {
                    if (config.fulltypes == CV8)
                        result += 2;
                    result += 6 + cv_stringbytes(id);
                }
                result = cv_align(NULL, result);
            }
            else
            {
                idx_t typidx = cv_typidx(Type_toCtype(vd->type));
                unsigned attribute = PROTtoATTR(vd->prot());
                assert((attribute & ~3) == 0);
                switch (config.fulltypes)
                {
                    case CV8:
                        if (vd->isField())
                        {
                            TOWORD(p,LF_MEMBER_V3);
                            TOWORD(p + 2,attribute);
                            TOLONG(p + 4,typidx);
                            cv4_storenumeric(p + 8, vd->offset);
                            result = 8 + cv4_numericbytes(vd->offset);
                            result += cv_namestring(p + result, id);
                        }
                        else if (vd->isStatic())
                        {
                            TOWORD(p,LF_STMEMBER_V3);
                            TOWORD(p + 2,attribute);
                            TOLONG(p + 4,typidx);
                            result = 8;
                            result += cv_namestring(p + result, id);
                        }
                        break;

                    case CV4:
                        if (vd->isField())
                        {
                            TOWORD(p,LF_MEMBER);
                            TOWORD(p + 2,typidx);
                            TOWORD(p + 4,attribute);
                            cv4_storenumeric(p + 6, vd->offset);
                            result = 6 + cv4_numericbytes(vd->offset);
                            result += cv_namestring(p + result, id);
                        }
                        else if (vd->isStatic())
                        {
                            TOWORD(p,LF_STMEMBER);
                            TOWORD(p + 2,typidx);
                            TOWORD(p + 4,attribute);
                            result = 6;
                            result += cv_namestring(p + result, id);
                        }
                        break;

                     default:
                        assert(0);
                }

                result = cv_align(p + result, result);
        #ifdef DEBUG
                int save = result;
                result = 0;
                p = NULL;
                visit(vd);
                assert(result == save);
        #endif
            }
        }
예제 #8
0
파일: tocvdebug.c 프로젝트: dacki/dmd
unsigned cv4_memfunctypidx(FuncDeclaration *fd)
{
    //printf("cv4_memfunctypidx(fd = '%s')\n", fd->toChars());

    type *t = Type_toCtype(fd->type);
    AggregateDeclaration *ad = fd->isMember2();
    if (ad)
    {
        // It's a member function, which gets a special type record

        idx_t thisidx;
        if (fd->isStatic())
            thisidx = dttab4[TYvoid];
        else
        {
            assert(ad->handleType());
            thisidx = cv4_typidx(Type_toCtype(ad->handleType()));
        }

        unsigned nparam;
        idx_t paramidx = cv4_arglist(t,&nparam);

        unsigned char call = cv4_callconv(t);

        debtyp_t *d;
        switch (config.fulltypes)
        {
            case CV4:
            {
                d = debtyp_alloc(18);
                unsigned char *p = d->data;
                TOWORD(p,LF_MFUNCTION);
                TOWORD(p + 2,cv4_typidx(t->Tnext));
                TOWORD(p + 4,cv4_typidx(Type_toCtype(ad->type)));
                TOWORD(p + 6,thisidx);
                p[8] = call;
                p[9] = 0;                               // reserved
                TOWORD(p + 10,nparam);
                TOWORD(p + 12,paramidx);
                TOLONG(p + 14,0);                       // thisadjust
                break;
            }
            case CV8:
            {
                d = debtyp_alloc(26);
                unsigned char *p = d->data;
                TOWORD(p,0x1009);
                TOLONG(p + 2,cv4_typidx(t->Tnext));
                TOLONG(p + 6,cv4_typidx(Type_toCtype(ad->type)));
                TOLONG(p + 10,thisidx);
                p[14] = call;
                p[15] = 0;                               // reserved
                TOWORD(p + 16,nparam);
                TOLONG(p + 18,paramidx);
                TOLONG(p + 22,0);                       // thisadjust
                break;
            }
            default:
                assert(0);
        }
        return cv_debtyp(d);
    }
    return cv4_typidx(t);
}
예제 #9
0
파일: tocvdebug.c 프로젝트: dacki/dmd
void toDebug(ClassDeclaration *cd)
{
    idx_t typidx = 0;

    //printf("ClassDeclaration::toDebug('%s')\n", cd->toChars());

    assert(config.fulltypes >= CV4);
    if (cd->isAnonymous())
        return /*0*/;

    if (typidx)                 // if reference already generated
        return /*typidx*/;      // use already existing reference

    targ_size_t size;
    unsigned property = 0;
    if (!cd->members)
    {
        size = 0;
        property |= 0x80;               // forward reference
    }
    else
        size = cd->structsize;

    if (cd->parent->isAggregateDeclaration()) // if class is nested
        property |= 8;
    if (cd->ctor || cd->dtors.dim)
        property |= 2;          // class has ctors and/or dtors
//    if (st->Sopoverload)
//      property |= 4;          // class has overloaded operators
//    if (st->Scastoverload)
//      property |= 0x40;               // class has casting methods
//    if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug))
//      property |= 0x20;               // class has overloaded assignment

    const char *id = cd->isCPPinterface() ? cd->ident->toChars() : cd->toPrettyChars(true);
    unsigned leaf = config.fulltypes == CV8 ? LF_CLASS_V3 : LF_CLASS;

    unsigned numidx = (leaf == LF_CLASS_V3) ? 18 : 12;
    unsigned len = numidx + cv4_numericbytes(size);
    debtyp_t *d = debtyp_alloc(len + cv_stringbytes(id));
    cv4_storenumeric(d->data + numidx,size);
    len += cv_namestring(d->data + len,id);

    idx_t vshapeidx = 0;
    if (1)
    {
        size_t n = cd->vtbl.dim;                   // number of virtual functions
        if (n)
        {   // 4 bits per descriptor
            debtyp_t *vshape = debtyp_alloc(4 + (n + 1) / 2);
            TOWORD(vshape->data,LF_VTSHAPE);
            TOWORD(vshape->data + 2,n);

            n = 0;
            unsigned char descriptor = 0;
            for (size_t i = 0; i < cd->vtbl.dim; i++)
            {
                FuncDeclaration *fd = (FuncDeclaration *)cd->vtbl[i];
                //if (intsize == 4)
                    descriptor |= 5;
                vshape->data[4 + n / 2] = descriptor;
                descriptor <<= 4;
                n++;
            }
            vshapeidx = cv_debtyp(vshape);
        }
    }
    if (leaf == LF_CLASS)
    {
        TOWORD(d->data + 8,0);          // dList
        TOWORD(d->data + 10,vshapeidx);
    }
    else if (leaf == LF_CLASS_V3)
    {
        TOLONG(d->data + 10,0);         // dList
        TOLONG(d->data + 14,vshapeidx);
    }
    TOWORD(d->data,leaf);

    // Assign a number to prevent infinite recursion if a struct member
    // references the same struct.
    unsigned length_save = d->length;
    d->length = 0;                      // so cv_debtyp() will allocate new
    typidx = cv_debtyp(d);
    d->length = length_save;            // restore length

    if (!cd->members)                       // if reference only
    {
        if (leaf == LF_CLASS_V3)
        {
            TOWORD(d->data + 2,0);          // count: number of fields is 0
            TOLONG(d->data + 6,0);          // field list is 0
            TOWORD(d->data + 4,property);
        }
        else
        {
            TOWORD(d->data + 2,0);          // count: number of fields is 0
            TOWORD(d->data + 4,0);          // field list is 0
            TOWORD(d->data + 6,property);
        }
        return /*typidx*/;
    }

    // Compute the number of fields (nfields), and the length of the fieldlist record (fnamelen)
    CvMemberCount mc;
    mc.nfields = 0;
    mc.fnamelen = 2;

    /* Adding in the base classes causes VS 2010 debugger to refuse to display any
     * of the fields. I have not been able to determine why.
     * (Could it be because the base class is "forward referenced"?)
     * It does work with VS 2012.
     */
    bool addInBaseClasses = true;
    if (addInBaseClasses)
    {
        // Add in base classes
        for (size_t i = 0; i < cd->baseclasses->dim; i++)
        {
            BaseClass *bc = (*cd->baseclasses)[i];
            mc.nfields++;
            unsigned elementlen = 4 + cgcv.sz_idx + cv4_numericbytes(bc->offset);
            elementlen = cv_align(NULL, elementlen);
            mc.fnamelen += elementlen;
        }
    }

    for (size_t i = 0; i < cd->members->dim; i++)
    {
        Dsymbol *s = (*cd->members)[i];
        s->apply(&cv_mem_count, &mc);
    }
    if (config.fulltypes != CV8 && mc.fnamelen > CV4_NAMELENMAX)
    {   // Too long, fail gracefully
        mc.nfields = 0;
        mc.fnamelen = 2;
    }
    unsigned nfields = mc.nfields;
    unsigned fnamelen = mc.fnamelen;

    int count = nfields;
    TOWORD(d->data + 2,count);

    // Generate fieldlist type record
    debtyp_t *dt = debtyp_alloc(fnamelen);
    unsigned char *p = dt->data;

    // And fill it in
    TOWORD(p,config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST);
    p += 2;

    if (nfields)        // if we didn't overflow
    {
        if (addInBaseClasses)
        {
            // Add in base classes
            for (size_t i = 0; i < cd->baseclasses->dim; i++)
            {
                BaseClass *bc = (*cd->baseclasses)[i];
                idx_t typidx = cv4_typidx(Type_toCtype(bc->sym->type)->Tnext);
                unsigned attribute = PROTtoATTR(bc->protection);

                unsigned elementlen;
                switch (config.fulltypes)
                {
                    case CV8:
                        TOWORD(p, LF_BCLASS_V2);
                        TOWORD(p + 2,attribute);
                        TOLONG(p + 4,typidx);
                        elementlen = 8;
                        break;

                    case CV4:
                        TOWORD(p, LF_BCLASS);
                        TOWORD(p + 2,typidx);
                        TOWORD(p + 4,attribute);
                        elementlen = 6;
                        break;
                }

                cv4_storenumeric(p + elementlen, bc->offset);
                elementlen += cv4_numericbytes(bc->offset);
                elementlen = cv_align(p + elementlen, elementlen);
                p += elementlen;
            }
        }

        for (size_t i = 0; i < cd->members->dim; i++)
        {
            Dsymbol *s = (*cd->members)[i];
            s->apply(&cv_mem_p, &p);
        }
    }

    //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data);
    assert(p - dt->data == fnamelen);
    idx_t fieldlist = cv_debtyp(dt);

    TOWORD(d->data + 2,count);
    if (config.fulltypes == CV8)
    {
        TOWORD(d->data + 4,property);
        TOLONG(d->data + 6,fieldlist);
    }
    else
    {
        TOWORD(d->data + 4,fieldlist);
        TOWORD(d->data + 6,property);
    }

//    cv4_outsym(s);

    if (config.fulltypes == CV8)
        cv8_udt(id, typidx);
    else
    {
        size_t idlen = strlen(id);
        unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + idlen);

        // Output a 'user-defined type' for the tag name
        TOWORD(debsym + 2,S_UDT);
        TOIDX(debsym + 4,typidx);
        unsigned length = 2 + 2 + cgcv.sz_idx;
        length += cv_namestring(debsym + length,id);
        TOWORD(debsym,length - 2);

        assert(length <= 40 + idlen);
        objmod->write_bytes(SegData[DEBSYM],length,debsym);
    }

//    return typidx;
}
예제 #10
0
파일: tocvdebug.c 프로젝트: dacki/dmd
unsigned cv4_Denum(EnumDeclaration *e)
{
    //dbg_printf("cv4_Denum(%s)\n", e->toChars());
    unsigned property = 0;
        if (!e->members || !e->memtype || !e->memtype->isintegral())
        property |= 0x80;               // enum is forward referenced or non-integer

    // Compute the number of fields, and the length of the fieldlist record
    unsigned nfields = 0;
    unsigned fnamelen = 2;
    if (!property)
    {
        for (size_t i = 0; i < e->members->dim; i++)
        {   EnumMember *sf = (*e->members)[i]->isEnumMember();
            if (sf)
            {
                dinteger_t value = sf->value->toInteger();
                unsigned fnamelen1 = fnamelen;

                // store only member's simple name
                fnamelen += 4 + cv4_numericbytes(value) + cv_stringbytes(sf->toChars());

                if (config.fulltypes != CV8)
                {
                    /* Optlink dies on longer ones, so just truncate
                     */
                    if (fnamelen > CV4_NAMELENMAX)
                    {   fnamelen = fnamelen1;       // back up
                        break;                      // and skip the rest
                    }
                }

                nfields++;
            }
        }
    }

    const char *id = e->toPrettyChars();
    unsigned len;
    debtyp_t *d;
    unsigned memtype = e->memtype ? cv4_typidx(Type_toCtype(e->memtype)) : 0;
    switch (config.fulltypes)
    {
        case CV8:
            len = 14;
            d = debtyp_alloc(len + cv_stringbytes(id));
            TOWORD(d->data,LF_ENUM_V3);
            TOLONG(d->data + 6,memtype);
            TOWORD(d->data + 4,property);
            len += cv_namestring(d->data + len,id);
            break;

        case CV4:
            len = 10;
            d = debtyp_alloc(len + cv_stringbytes(id));
            TOWORD(d->data,LF_ENUM);
            TOWORD(d->data + 4,memtype);
            TOWORD(d->data + 8,property);
            len += cv_namestring(d->data + len,id);
            break;

        default:
            assert(0);
    }
    unsigned length_save = d->length;
    d->length = 0;                      // so cv_debtyp() will allocate new
    idx_t typidx = cv_debtyp(d);
    d->length = length_save;            // restore length

    TOWORD(d->data + 2,nfields);

    unsigned fieldlist = 0;
    if (!property)                      // if forward reference, then fieldlist is 0
    {
        // Generate fieldlist type record
        debtyp_t *dt = debtyp_alloc(fnamelen);
        TOWORD(dt->data,(config.fulltypes == CV8) ? LF_FIELDLIST_V2 : LF_FIELDLIST);

        // And fill it in
        unsigned j = 2;
        unsigned fieldi = 0;
        for (size_t i = 0; i < e->members->dim; i++)
        {   EnumMember *sf = (*e->members)[i]->isEnumMember();

            if (sf)
            {
                fieldi++;
                if (fieldi > nfields)
                    break;                  // chop off the rest

                dinteger_t value = sf->value->toInteger();
                TOWORD(dt->data + j,(config.fulltypes == CV8) ? LF_ENUMERATE_V3 : LF_ENUMERATE);
                unsigned attribute = 0;
                TOWORD(dt->data + j + 2,attribute);
                cv4_storenumeric(dt->data + j + 4,value);
                j += 4 + cv4_numericbytes(value);
                // store only member's simple name
                j += cv_namestring(dt->data + j, sf->toChars());

                // If enum is not a member of a class, output enum members as constants
    //          if (!isclassmember(s))
    //          {
    //              cv4_outsym(sf);
    //          }
            }
        }
        assert(j == fnamelen);
        fieldlist = cv_debtyp(dt);
    }

    if (config.fulltypes == CV8)
        TOLONG(d->data + 10,fieldlist);
    else
        TOWORD(d->data + 6,fieldlist);

//    cv4_outsym(s);
    return typidx;
}
예제 #11
0
파일: tocsym.c 프로젝트: monarchdodra/dmd
        void visit(FuncDeclaration *fd)
        {
            if (!fd->csym)
            {
                const char *id = mangleExact(fd);

                //printf("FuncDeclaration::toSymbol(%s %s)\n", fd->kind(), fd->toChars());
                //printf("\tid = '%s'\n", id);
                //printf("\ttype = %s\n", fd->type->toChars());
                Symbol *s = symbol_calloc(id);
                slist_add(s);

                s->prettyIdent = fd->toPrettyChars();
                s->Sclass = SCglobal;
                symbol_func(s);
                func_t *f = s->Sfunc;
                if (fd->isVirtual() && fd->vtblIndex != -1)
                    f->Fflags |= Fvirtual;
                else if (fd->isMember2() && fd->isStatic())
                    f->Fflags |= Fstatic;
                f->Fstartline.Slinnum = fd->loc.linnum;
                f->Fstartline.Scharnum = fd->loc.charnum;
                f->Fstartline.Sfilename = (char *)fd->loc.filename;
                if (fd->endloc.linnum)
                {
                    f->Fendline.Slinnum = fd->endloc.linnum;
                    f->Fendline.Scharnum = fd->endloc.charnum;
                    f->Fendline.Sfilename = (char *)fd->endloc.filename;
                }
                else
                {
                    f->Fendline.Slinnum = fd->loc.linnum;
                    f->Fendline.Scharnum = fd->loc.charnum;
                    f->Fendline.Sfilename = (char *)fd->loc.filename;
                }
                TYPE *t = Type_toCtype(fd->type);

                mangle_t msave = t->Tmangle;
                if (fd->isMain())
                {
                    t->Tty = TYnfunc;
                    t->Tmangle = mTYman_c;
                }
                else
                {
                    switch (fd->linkage)
                    {
                    case LINKwindows:
                        t->Tmangle = mTYman_std;
                        break;

                    case LINKpascal:
                        t->Tty = TYnpfunc;
                        t->Tmangle = mTYman_pas;
                        break;

                    case LINKc:
                        t->Tmangle = mTYman_c;
                        break;

                    case LINKd:
                        t->Tmangle = mTYman_d;
                        break;
                    case LINKcpp:
                        s->Sflags |= SFLpublic;
                        if (fd->isThis() && !global.params.is64bit && global.params.isWindows)
                        {
                            if (((TypeFunction *)fd->type)->varargs == 1)
                            {
                                t->Tty = TYnfunc;
                            }
                            else
                            {
                                t->Tty = TYmfunc;
                            }
                        }
                        t->Tmangle = mTYman_d;
                        break;
                    default:
                        printf("linkage = %d\n", fd->linkage);
                        assert(0);
                    }
                }

                if (msave)
                    assert(msave == t->Tmangle);
                //printf("Tty = %x, mangle = x%x\n", t->Tty, t->Tmangle);
                t->Tcount++;
                s->Stype = t;
                //s->Sfielddef = this;

                fd->csym = s;
            }
            result = fd->csym;
        }
예제 #12
0
파일: tocsym.c 프로젝트: monarchdodra/dmd
        void visit(VarDeclaration *vd)
        {
            //printf("VarDeclaration::toSymbol(%s)\n", vd->toChars());
            assert(!vd->needThis());
            if (!vd->csym)
            {
                const char *id;
                if (vd->isDataseg())
                    id = mangle(vd);
                else
                    id = vd->ident->toChars();
                Symbol *s = symbol_calloc(id);
                s->Salignment = vd->alignment;
                if (vd->storage_class & STCtemp)
                    s->Sflags |= SFLartifical;

                TYPE *t;
                if (vd->storage_class & (STCout | STCref))
                {
                    // should be TYref, but problems in back end
                    t = type_pointer(Type_toCtype(vd->type));
                }
                else if (vd->storage_class & STClazy)
                {
                    if (config.exe == EX_WIN64 && vd->isParameter())
                        t = type_fake(TYnptr);
                    else
                        t = type_fake(TYdelegate);          // Tdelegate as C type
                    t->Tcount++;
                }
                else if (vd->isParameter())
                {
                    if (config.exe == EX_WIN64 && vd->type->size(Loc()) > REGSIZE)
                    {
                        // should be TYref, but problems in back end
                        t = type_pointer(Type_toCtype(vd->type));
                    }
                    else
                    {
                        t = Type_toCtype(vd->type);
                        t->Tcount++;
                    }
                }
                else
                {
                    t = Type_toCtype(vd->type);
                    t->Tcount++;
                }

                if (vd->isDataseg())
                {
                    if (vd->isThreadlocal())
                    {
                        /* Thread local storage
                         */
                        TYPE *ts = t;
                        ts->Tcount++;   // make sure a different t is allocated
                        type_setty(&t, t->Tty | mTYthread);
                        ts->Tcount--;

                        if (global.params.vtls)
                        {
                            char *p = vd->loc.toChars();
                            fprintf(global.stdmsg, "%s: %s is thread local\n", p ? p : "", vd->toChars());
                            if (p)
                                mem.free(p);
                        }
                    }
                    s->Sclass = SCextern;
                    s->Sfl = FLextern;
                    slist_add(s);
                    /* if it's global or static, then it needs to have a qualified but unmangled name.
                     * This gives some explanation of the separation in treating name mangling.
                     * It applies to PDB format, but should apply to CV as PDB derives from CV.
                     *    http://msdn.microsoft.com/en-us/library/ff553493(VS.85).aspx
                     */
                    s->prettyIdent = vd->toPrettyChars();
                }
                else
                {
                    s->Sclass = SCauto;
                    s->Sfl = FLauto;

                    if (vd->nestedrefs.dim)
                    {
                        /* Symbol is accessed by a nested function. Make sure
                         * it is not put in a register, and that the optimizer
                         * assumes it is modified across function calls and pointer
                         * dereferences.
                         */
                        //printf("\tnested ref, not register\n");
                        type_setcv(&t, t->Tty | mTYvolatile);
                    }
                }

                if (vd->ident == Id::va_argsave)
                {
                    /* __va_argsave is set outside of the realm of the optimizer,
                     * so we tell the optimizer to leave it alone
                     */
                    type_setcv(&t, t->Tty | mTYvolatile);
                }

                mangle_t m = 0;
                switch (vd->linkage)
                {
                case LINKwindows:
                    m = mTYman_std;
                    break;

                case LINKpascal:
                    m = mTYman_pas;
                    break;

                case LINKc:
                    m = mTYman_c;
                    break;

                case LINKd:
                    m = mTYman_d;
                    break;
                case LINKcpp:
                    s->Sflags |= SFLpublic;
                    m = mTYman_d;
                    break;
                default:
                    printf("linkage = %d\n", vd->linkage);
                    assert(0);
                }

                type_setmangle(&t, m);
                s->Stype = t;

                vd->csym = s;
            }
            result = vd->csym;
        }
예제 #13
0
/*************************************
 * Closures are implemented by taking the local variables that
 * need to survive the scope of the function, and copying them
 * into a gc allocated chuck of memory. That chunk, called the
 * closure here, is inserted into the linked list of stack
 * frames instead of the usual stack frame.
 *
 * buildClosure() inserts code just after the function prolog
 * is complete. It allocates memory for the closure, allocates
 * a local variable (sclosure) to point to it, inserts into it
 * the link to the enclosing frame, and copies into it the parameters
 * that are referred to in nested functions.
 * In VarExp::toElem and SymOffExp::toElem, when referring to a
 * variable that is in a closure, takes the offset from sclosure rather
 * than from the frame pointer.
 *
 * getEthis() and NewExp::toElem need to use sclosure, if set, rather
 * than the current frame pointer.
 */
void buildClosure(FuncDeclaration *fd, IRState *irs)
{
    if (fd->needsClosure())
    {
        // Generate closure on the heap
        // BUG: doesn't capture variadic arguments passed to this function

        /* BUG: doesn't handle destructors for the local variables.
         * The way to do it is to make the closure variables the fields
         * of a class object:
         *    class Closure {
         *        vtbl[]
         *        monitor
         *        ptr to destructor
         *        sthis
         *        ... closure variables ...
         *        ~this() { call destructor }
         *    }
         */
        //printf("FuncDeclaration::buildClosure() %s\n", toChars());

        /* Generate type name for closure struct */
        const char *name1 = "CLOSURE.";
        const char *name2 = fd->toPrettyChars();
        size_t namesize = strlen(name1)+strlen(name2)+1;
        char *closname = (char *) calloc(namesize, sizeof(char));
        strcat(strcat(closname, name1), name2);

        /* Build type for closure */
        type *Closstru = type_struct_class(closname, Target::ptrsize, 0, NULL, NULL, false, false, true);
        symbol_struct_addField(Closstru->Ttag, "__chain", Type_toCtype(Type::tvoidptr), 0);

        Symbol *sclosure;
        sclosure = symbol_name("__closptr", SCauto, type_pointer(Closstru));
        sclosure->Sflags |= SFLtrue | SFLfree;
        symbol_add(sclosure);
        irs->sclosure = sclosure;

        unsigned offset = Target::ptrsize;      // leave room for previous sthis
        for (size_t i = 0; i < fd->closureVars.dim; i++)
        {
            VarDeclaration *v = fd->closureVars[i];
            //printf("closure var %s\n", v->toChars());
            assert(v->isVarDeclaration());

            if (v->needsAutoDtor())
            {
                /* Because the value needs to survive the end of the scope!
                 */
                v->error("has scoped destruction, cannot build closure");
            }
            if (v->isargptr)
            {
                /* See Bugzilla 2479
                 * This is actually a bug, but better to produce a nice
                 * message at compile time rather than memory corruption at runtime
                 */
                v->error("cannot reference variadic arguments from closure");
            }
            /* Align and allocate space for v in the closure
             * just like AggregateDeclaration::addField() does.
             */
            unsigned memsize;
            unsigned memalignsize;
            structalign_t xalign;
            if (v->storage_class & STClazy)
            {
                /* Lazy variables are really delegates,
                 * so give same answers that TypeDelegate would
                 */
                memsize = Target::ptrsize * 2;
                memalignsize = memsize;
                xalign = STRUCTALIGN_DEFAULT;
            }
            else if (ISWIN64REF(v))
            {
                memsize = v->type->size();
                memalignsize = v->type->alignsize();
                xalign = v->alignment;
            }
            else if (ISREF(v, NULL))
            {
                // reference parameters are just pointers
                memsize = Target::ptrsize;
                memalignsize = memsize;
                xalign = STRUCTALIGN_DEFAULT;
            }
            else
            {
                memsize = v->type->size();
                memalignsize = v->type->alignsize();
                xalign = v->alignment;
            }
            AggregateDeclaration::alignmember(xalign, memalignsize, &offset);
            v->offset = offset;
            offset += memsize;

            /* Set Sscope to closure */
            Symbol *vsym = toSymbol(v);
            assert(vsym->Sscope == NULL);
            vsym->Sscope = sclosure;

            /* Add variable as closure type member */
            symbol_struct_addField(Closstru->Ttag, vsym->Sident, vsym->Stype, v->offset);
            //printf("closure field %s: memalignsize: %i, offset: %i\n", vsym->Sident, memalignsize, v->offset);

            /* Can't do nrvo if the variable is put in a closure, since
             * what the shidden points to may no longer exist.
             */
            if (fd->nrvo_can && fd->nrvo_var == v)
            {
                fd->nrvo_can = 0;
            }
        }
        // offset is now the size of the closure
        Closstru->Ttag->Sstruct->Sstructsize = offset;

        // Allocate memory for the closure
        elem *e = el_long(TYsize_t, offset);
        e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM_ALLOCMEMORY)), e);
        toTraceGC(irs, e, &fd->loc);

        // Assign block of memory to sclosure
        //    sclosure = allocmemory(sz);
        e = el_bin(OPeq, TYvoid, el_var(sclosure), e);

        // Set the first element to sthis
        //    *(sclosure + 0) = sthis;
        elem *ethis;
        if (irs->sthis)
            ethis = el_var(irs->sthis);
        else
            ethis = el_long(TYnptr, 0);
        elem *ex = el_una(OPind, TYnptr, el_var(sclosure));
        ex = el_bin(OPeq, TYnptr, ex, ethis);
        e = el_combine(e, ex);

        // Copy function parameters into closure
        for (size_t i = 0; i < fd->closureVars.dim; i++)
        {
            VarDeclaration *v = fd->closureVars[i];

            if (!v->isParameter())
                continue;
            tym_t tym = totym(v->type);
            bool win64ref = ISWIN64REF(v);
            if (win64ref)
            {
                if (v->storage_class & STClazy)
                    tym = TYdelegate;
            }
            else if (ISREF(v, NULL))
                tym = TYnptr;   // reference parameters are just pointers
            else if (v->storage_class & STClazy)
                tym = TYdelegate;
            ex = el_bin(OPadd, TYnptr, el_var(sclosure), el_long(TYsize_t, v->offset));
            ex = el_una(OPind, tym, ex);
            elem *ev = el_var(toSymbol(v));
            if (win64ref)
            {
                ev->Ety = TYnptr;
                ev = el_una(OPind, tym, ev);
                if (tybasic(ev->Ety) == TYstruct || tybasic(ev->Ety) == TYarray)
                    ev->ET = Type_toCtype(v->type);
            }
            if (tybasic(ex->Ety) == TYstruct || tybasic(ex->Ety) == TYarray)
            {
                ::type *t = Type_toCtype(v->type);
                ex->ET = t;
                ex = el_bin(OPstreq, tym, ex, ev);
                ex->ET = t;
            }
            else
                ex = el_bin(OPeq, tym, ex, ev);

            e = el_combine(e, ex);
        }

        block_appendexp(irs->blx->curblock, e);
    }
}
예제 #14
0
파일: s2ir.c 프로젝트: Faianca/dmd
    void visit(ReturnStatement *s)
    {
        Blockx *blx = irs->blx;
        enum BC bc;

        incUsage(irs, s->loc);
        if (s->exp)
        {
            elem *e;

            FuncDeclaration *func = irs->getFunc();
            assert(func);
            assert(func->type->ty == Tfunction);
            TypeFunction *tf = (TypeFunction *)(func->type);

            RET retmethod = retStyle(tf);
            if (retmethod == RETstack)
            {
                elem *es;

                /* If returning struct literal, write result
                 * directly into return value
                 */
                if (s->exp->op == TOKstructliteral)
                {
                    StructLiteralExp *se = (StructLiteralExp *)s->exp;
                    char save[sizeof(StructLiteralExp)];
                    memcpy(save, (void*)se, sizeof(StructLiteralExp));
                    se->sym = irs->shidden;
                    se->soffset = 0;
                    se->fillHoles = 1;
                    e = toElemDtor(s->exp, irs);
                    memcpy((void*)se, save, sizeof(StructLiteralExp));
                }
                else
                    e = toElemDtor(s->exp, irs);
                assert(e);

                if (s->exp->op == TOKstructliteral ||
                    (func->nrvo_can && func->nrvo_var))
                {
                    // Return value via hidden pointer passed as parameter
                    // Write exp; return shidden;
                    es = e;
                }
                else
                {
                    // Return value via hidden pointer passed as parameter
                    // Write *shidden=exp; return shidden;
                    int op;
                    tym_t ety;

                    ety = e->Ety;
                    es = el_una(OPind,ety,el_var(irs->shidden));
                    op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq;
                    es = el_bin(op, ety, es, e);
                    if (op == OPstreq)
                        es->ET = Type_toCtype(s->exp->type);
                }
                e = el_var(irs->shidden);
                e = el_bin(OPcomma, e->Ety, es, e);
            }
            else if (tf->isref)
            {
                // Reference return, so convert to a pointer
                e = toElemDtor(s->exp, irs);
                e = addressElem(e, s->exp->type->pointerTo());
            }
            else
            {
                e = toElemDtor(s->exp, irs);
                assert(e);
            }
            elem_setLoc(e, s->loc);
            block_appendexp(blx->curblock, e);
            bc = BCretexp;
        }
        else
            bc = BCret;

        if (block *finallyBlock = irs->getFinallyBlock())
        {
            assert(finallyBlock->BC == BC_finally);
            blx->curblock->appendSucc(finallyBlock);
        }

        block_next(blx, bc, NULL);
    }