Exemple #1
0
Fichier : toir.c Projet : dheld/dmd
elem *setEthis(Loc loc, IRState *irs, elem *ey, AggregateDeclaration *ad)
{
    elem *ethis;
    FuncDeclaration *thisfd = irs->getFunc();
    int offset = 0;
    Dsymbol *cdp = ad->toParent2();     // class/func we're nested in

    //printf("setEthis(ad = %s, cdp = %s, thisfd = %s)\n", ad->toChars(), cdp->toChars(), thisfd->toChars());

    if (cdp == thisfd)
    {   /* Class we're new'ing is a local class in this function:
         *      void thisfd() { class ad { } }
         */
        if (irs->sclosure)
            ethis = el_var(irs->sclosure);
        else if (irs->sthis)
        {
            if (thisfd->hasNestedFrameRefs())
            {
                ethis = el_ptr(irs->sthis);
            }
            else
                ethis = el_var(irs->sthis);
        }
        else
        {
            ethis = el_long(TYnptr, 0);
            if (thisfd->hasNestedFrameRefs())
            {
                ethis->Eoper = OPframeptr;
            }
        }
    }
    else if (thisfd->vthis &&
          (cdp == thisfd->toParent2() ||
           (cdp->isClassDeclaration() &&
            cdp->isClassDeclaration()->isBaseOf(thisfd->toParent2()->isClassDeclaration(), &offset)
           )
          )
        )
    {   /* Class we're new'ing is at the same level as thisfd
         */
        assert(offset == 0);    // BUG: should handle this case
        ethis = el_var(irs->sthis);
    }
    else
    {
        ethis = getEthis(loc, irs, ad->toParent2());
        ethis = el_una(OPaddr, TYnptr, ethis);
    }

    ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, ad->vthis->offset));
    ey = el_una(OPind, TYnptr, ey);
    ey = el_bin(OPeq, TYnptr, ey, ethis);
    return ey;
}
Exemple #2
0
/*************************
 * Initialize the hidden aggregate member, vthis, with
 * the context pointer.
 * Returns:
 *      *(ey + ad.vthis.offset) = this;
 */
elem *setEthis(Loc loc, IRState *irs, elem *ey, AggregateDeclaration *ad)
{
    elem *ethis;
    FuncDeclaration *thisfd = irs->getFunc();
    int offset = 0;
    Dsymbol *adp = ad->toParent2();     // class/func we're nested in

    //printf("[%s] setEthis(ad = %s, adp = %s, thisfd = %s)\n", loc.toChars(), ad->toChars(), adp->toChars(), thisfd->toChars());

    if (adp == thisfd)
    {
        ethis = getEthis(loc, irs, ad);
    }
    else if (thisfd->vthis &&
          (adp == thisfd->toParent2() ||
           (adp->isClassDeclaration() &&
            adp->isClassDeclaration()->isBaseOf(thisfd->toParent2()->isClassDeclaration(), &offset)
           )
          )
        )
    {
        /* Class we're new'ing is at the same level as thisfd
         */
        assert(offset == 0);    // BUG: should handle this case
        ethis = el_var(irs->sthis);
    }
    else
    {
        ethis = getEthis(loc, irs, adp);
        FuncDeclaration *fdp = adp->isFuncDeclaration();
        if (fdp && fdp->hasNestedFrameRefs())
            ethis = el_una(OPaddr, TYnptr, ethis);
    }

    ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, ad->vthis->offset));
    ey = el_una(OPind, TYnptr, ey);
    ey = el_bin(OPeq, TYnptr, ey, ethis);
    return ey;
}
Exemple #3
0
/******************************************
 * Return elem that evaluates to the static frame pointer for function fd.
 * If fd is a member function, the returned expression will compute the value
 * of fd's 'this' variable.
 * This routine is critical for implementing nested functions.
 */
elem *getEthis(Loc loc, IRState *irs, Dsymbol *fd)
{
    elem *ethis;
    FuncDeclaration *thisfd = irs->getFunc();
    Dsymbol *fdparent = fd->toParent2();
    Dsymbol *fdp = fdparent;

    /* These two are compiler generated functions for the in and out contracts,
     * and are called from an overriding function, not just the one they're
     * nested inside, so this hack is so they'll pass
     */
    if (fdparent != thisfd && (fd->ident == Id::require || fd->ident == Id::ensure))
    {
        FuncDeclaration *fdthis = thisfd;
        for (size_t i = 0; ; )
        {
            if (i == fdthis->foverrides.dim)
            {
                if (i == 0)
                    break;
                fdthis = fdthis->foverrides[0];
                i = 0;
                continue;
            }
            if (fdthis->foverrides[i] == fdp)
            {
                fdparent = thisfd;
                break;
            }
            i++;
        }
    }

    //printf("[%s] getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", loc.toChars(), thisfd->toPrettyChars(), fd->toPrettyChars(), fdparent->toPrettyChars());
    if (fdparent == thisfd)
    {
        /* Going down one nesting level, i.e. we're calling
         * a nested function from its enclosing function.
         */
        if (irs->sclosure && !(fd->ident == Id::require || fd->ident == Id::ensure))
        {
            ethis = el_var(irs->sclosure);
        }
        else if (irs->sthis)
        {
            // We have a 'this' pointer for the current function

            /* If no variables in the current function's frame are
             * referenced by nested functions, then we can 'skip'
             * adding this frame into the linked list of stack
             * frames.
             */
            if (thisfd->hasNestedFrameRefs())
            {
                /* Local variables are referenced, can't skip.
                 * Address of 'sthis' gives the 'this' for the nested
                 * function
                 */
                ethis = el_ptr(irs->sthis);
            }
            else
            {
                ethis = el_var(irs->sthis);
            }
        }
        else
        {
            /* No 'this' pointer for current function,
             */
            if (thisfd->hasNestedFrameRefs())
            {
                /* OPframeptr is an operator that gets the frame pointer
                 * for the current function, i.e. for the x86 it gets
                 * the value of EBP
                 */
                ethis = el_long(TYnptr, 0);
                ethis->Eoper = OPframeptr;
            }
            else
            {
                /* Use NULL if no references to the current function's frame
                 */
                ethis = el_long(TYnptr, 0);
            }
        }
    }
    else
    {
        if (!irs->sthis)                // if no frame pointer for this function
        {
            fd->error(loc, "is a nested function and cannot be accessed from %s", irs->getFunc()->toPrettyChars());
            return el_long(TYnptr, 0); // error recovery
        }

        /* Go up a nesting level, i.e. we need to find the 'this'
         * of an enclosing function.
         * Our 'enclosing function' may also be an inner class.
         */
        ethis = el_var(irs->sthis);
        Dsymbol *s = thisfd;
        while (fd != s)
        {
            FuncDeclaration *fdp = s->toParent2()->isFuncDeclaration();

            //printf("\ts = '%s'\n", s->toChars());
            thisfd = s->isFuncDeclaration();
            if (thisfd)
            {
                /* Enclosing function is a function.
                 */
                // Error should have been caught by front end
                assert(thisfd->isNested() || thisfd->vthis);
            }
            else
            {
                /* Enclosed by an aggregate. That means the current
                 * function must be a member function of that aggregate.
                 */
                AggregateDeclaration *ad = s->isAggregateDeclaration();
                if (!ad)
                {
                  Lnoframe:
                    irs->getFunc()->error(loc, "cannot get frame pointer to %s", fd->toPrettyChars());
                    return el_long(TYnptr, 0);      // error recovery
                }
                ClassDeclaration *cd = ad->isClassDeclaration();
                ClassDeclaration *cdx = fd->isClassDeclaration();
                if (cd && cdx && cdx->isBaseOf(cd, NULL))
                    break;
                StructDeclaration *sd = ad->isStructDeclaration();
                if (fd == sd)
                    break;
                if (!ad->isNested() || !ad->vthis)
                    goto Lnoframe;

                ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, ad->vthis->offset));
                ethis = el_una(OPind, TYnptr, ethis);
            }
            if (fdparent == s->toParent2())
                break;

            /* Remember that frames for functions that have no
             * nested references are skipped in the linked list
             * of frames.
             */
            if (fdp && fdp->hasNestedFrameRefs())
                ethis = el_una(OPind, TYnptr, ethis);

            s = s->toParent2();
            assert(s);
        }
    }
#if 0
    printf("ethis:\n");
    elem_print(ethis);
    printf("\n");
#endif
    return ethis;
}
Exemple #4
0
Expression *VarExp::doInline(InlineDoState *ids)
{
    //printf("VarExp::doInline(%s)\n", toChars());
    for (size_t i = 0; i < ids->from.dim; i++)
    {
        if (var == ids->from[i])
        {
            VarExp *ve = (VarExp *)copy();
            ve->var = (Declaration *)ids->to[i];
            return ve;
        }
    }
    if (ids->fd && var == ids->fd->vthis)
    {
        VarExp *ve = new VarExp(loc, ids->vthis);
        ve->type = type;
        return ve;
    }

    /* Inlining context pointer access for nested referenced variables.
     * For example:
     *      auto fun() {
     *        int i = 40;
     *        auto foo() {
     *          int g = 2;
     *          struct Result {
     *            auto bar() { return i + g; }
     *          }
     *          return Result();
     *        }
     *        return foo();
     *      }
     *      auto t = fun();
     * 'i' and 'g' are nested referenced variables in Result.bar(), so:
     *      auto x = t.bar();
     * should be inlined to:
     *      auto x = *(t.vthis.vthis + i->voffset) + *(t.vthis + g->voffset)
     */
    VarDeclaration *v = var->isVarDeclaration();
    if (v && v->nestedrefs.dim && ids->vthis)
    {
        Dsymbol *s = ids->fd;
        FuncDeclaration *fdv = v->toParent()->isFuncDeclaration();
        assert(fdv);
        Expression *ve = new VarExp(loc, ids->vthis);
        ve->type = ids->vthis->type;
        while (s != fdv)
        {
            FuncDeclaration *f = s->isFuncDeclaration();
            if (AggregateDeclaration *ad = s->isThis())
            {
                assert(ad->vthis);
                ve = new DotVarExp(loc, ve, ad->vthis);
                ve->type = ad->vthis->type;
                s = ad->toParent2();
            }
            else if (f && f->isNested())
            {
                assert(f->vthis);
                if (f->hasNestedFrameRefs())
                {
                    ve = new DotVarExp(loc, ve, f->vthis);
                    ve->type = f->vthis->type;
                }
                s = f->toParent2();
            }
            else
                assert(0);
            assert(s);
        }
        ve = new DotVarExp(loc, ve, v);
        ve->type = v->type;
        //printf("\t==> ve = %s, type = %s\n", ve->toChars(), ve->type->toChars());
        return ve;
    }

    return this;
}