view dmd/SymbolExp.d @ 178:e3afd1303184

Many small bugs fixed Made all classes derive from TObject to detect memory leaks (functionality is disabled for now) Began work on overriding backend memory allocations (to avoid memory leaks)
author korDen
date Sun, 17 Oct 2010 07:42:00 +0400
parents e28b18c23469
children cd48cb899aee
line wrap: on
line source

module dmd.SymbolExp;

import dmd.common;
import dmd.Expression;
import dmd.Declaration;
import dmd.Loc;
import dmd.IRState;
import dmd.TOK;
import dmd.TY;
import dmd.Type;
import dmd.SymOffExp;
import dmd.FuncDeclaration;
import dmd.VarDeclaration;
import dmd.backend.OPER;
import dmd.backend.TYM;
import dmd.backend.mTY;
import dmd.backend.SC;
import dmd.backend.elem;
import dmd.backend.Symbol;
import dmd.backend.Util;
import dmd.codegen.Util;

version(DMDV2)
class SymbolExp : Expression
{
	Declaration var;

	bool hasOverloads;

	this(Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
	{
		register();
		super(loc, op, size);
		assert(var);
		this.var = var;
		this.hasOverloads = hasOverloads;
	}

	override elem* toElem(IRState* irs)
	{
		Symbol* s;
		elem* e;
		tym_t tym;
		Type tb = (op == TOK.TOKsymoff) ? var.type.toBasetype() : type.toBasetype();
		int offset = (op == TOK.TOKsymoff) ? (cast(SymOffExp)this).offset : 0;
		FuncDeclaration fd;
		VarDeclaration v = var.isVarDeclaration();

		//printf("SymbolExp::toElem('%s') %p\n", toChars(), this);
		//printf("\tparent = '%s'\n", var.parent ? var.parent.toChars() : "null");
		if (op == TOK.TOKvar && var.needThis())
		{
			error("need 'this' to access member %s", toChars());
			return el_long(TYM.TYint, 0);
		}
		s = var.toSymbol();
		fd = null;
		if (var.toParent2())
			fd = var.toParent2().isFuncDeclaration();

		int nrvo = 0;
		if (fd && fd.nrvo_can && fd.nrvo_var == var)
		{
			s = fd.shidden;
			nrvo = 1;
		}

		if (s.Sclass == SC.SCauto || s.Sclass == SC.SCparameter)
		{
			if (fd && fd != irs.getFunc())
			{   
				// 'var' is a variable in an enclosing function.
				elem* ethis;
				int soffset;

				ethis = getEthis(loc, irs, fd);
				ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis);

				if (v && v.offset)
					soffset = v.offset;
				else
				{
					soffset = s.Soffset;
					/* If fd is a non-static member function of a class or struct,
					 * then ethis isn't the frame pointer.
					 * ethis is the 'this' pointer to the class/struct instance.
					 * We must offset it.
					 */
					if (fd.vthis)
					{
						soffset -= fd.vthis.toSymbol().Soffset;
					}
					//printf("\tSoffset = x%x, sthis.Soffset = x%x\n", s.Soffset, irs.sthis.Soffset);
				}

				if (!nrvo)
					soffset += offset;

				e = el_bin(OPER.OPadd, TYM.TYnptr, ethis, el_long(TYM.TYnptr, soffset));

				if (op == TOK.TOKvar)
					e = el_una(OPER.OPind, TYM.TYnptr, e);
				if (ISREF(var, tb))
					e = el_una(OPER.OPind, s.ty(), e);
				else if (op == TOK.TOKsymoff && nrvo)
				{   
					e = el_una(OPER.OPind, TYM.TYnptr, e);
					e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset));
				}
				goto L1;
			}
		}

		/* If var is a member of a closure
		 */
		if (v && v.offset)
		{	
			assert(irs.sclosure);
			e = el_var(irs.sclosure);
			e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, v.offset));
			if (op == TOK.TOKvar)
			{   
				e = el_una(OPER.OPind, type.totym(), e);
				if (tybasic(e.Ety) == TYM.TYstruct)
				e.Enumbytes = cast(uint)type.size();
				el_setLoc(e, loc);
			}
			if (ISREF(var, tb))
			{   
				e.Ety = TYM.TYnptr;
				e = el_una(OPER.OPind, s.ty(), e);
			}
			else if (op == TOK.TOKsymoff && nrvo)
			{   e = el_una(OPER.OPind, TYM.TYnptr, e);
				e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset));
			}
			else if (op == TOK.TOKsymoff)
			{
				e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset));
			}
			goto L1;
		}

		if (s.Sclass == SC.SCauto && s.Ssymnum == -1)
		{
			//printf("\tadding symbol\n");
			symbol_add(s);
		}

		if (var.isImportedSymbol())
		{
			assert(op == TOK.TOKvar);
			e = el_var(var.toImport());
			e = el_una(OPER.OPind,s.ty(),e);
		}
		else if (ISREF(var, tb))
		{	
			// Static arrays are really passed as pointers to the array
			// Out parameters are really references
			e = el_var(s);
			e.Ety = TYM.TYnptr;
			if (op == TOK.TOKvar)
				e = el_una(OPER.OPind, s.ty(), e);
			else if (offset)
					e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, offset));
		}
		else if (op == TOK.TOKvar)
			e = el_var(s);
		else
		{   
			e = nrvo ? el_var(s) : el_ptr(s);
			e = el_bin(OPER.OPadd, e.Ety, e, el_long(TYM.TYint, offset));
		}
	L1:
		if (op == TOK.TOKvar)
		{
			if (nrvo)
			{
				e.Ety = TYM.TYnptr;
				e = el_una(OPER.OPind, 0, e);
			}
			if (tb.ty == TY.Tfunction)
			{
				tym = s.Stype.Tty;
			}
			else
				tym = type.totym();
			e.Ejty = cast(ubyte)tym;
			e.Ety = e.Ejty;
			if (tybasic(tym) == TYM.TYstruct)
			{
				e.Enumbytes = cast(uint)type.size();
			}
			else if (tybasic(tym) == TYM.TYarray)
			{
				e.Ejty = TYM.TYstruct;
				e.Ety = e.Ejty;
				e.Enumbytes = cast(uint)type.size();
			}
		}
		el_setLoc(e,loc);
		return e;
	}
}