Mercurial > projects > ddmd
diff dmd/FuncDeclaration.d @ 73:ef02e2e203c2
Updating to dmd2.033
author | korDen |
---|---|
date | Sat, 28 Aug 2010 19:42:41 +0400 |
parents | 2e2a5c3f943a |
children | 7e0d548de9e6 |
line wrap: on
line diff
--- a/dmd/FuncDeclaration.d Sat Aug 28 16:19:48 2010 +0200 +++ b/dmd/FuncDeclaration.d Sat Aug 28 19:42:41 2010 +0400 @@ -4,6 +4,9 @@ import dmd.DotIdExp; import dmd.AddrExp; import dmd.TryFinallyStatement; +import dmd.TryCatchStatement; +import dmd.Catch; +import dmd.DeclarationStatement; import dmd.StaticDtorDeclaration; import dmd.GlobalExpressions; import dmd.PeelStatement; @@ -80,7 +83,6 @@ import dmd.Util; import dmd.BaseClass; import dmd.Module; -import dmd.ILS; import dmd.InlineCostState; import dmd.expression.Util; @@ -126,6 +128,10 @@ Statement frequire; Statement fensure; Statement fbody; + + FuncDeclarations foverrides; // functions this function overrides + FuncDeclaration fdrequire; // function that does the in contract + FuncDeclaration fdensure; // function that does the out contract Identifier outId; // identifier for out statement VarDeclaration vresult; // variable corresponding to outId @@ -142,10 +148,10 @@ DsymbolTable labtab; // statement label symbol table Declaration overnext; // next in overload list Loc endloc; // location of closing curly bracket - int vtblIndex = -1; // for member functions, index into vtbl[] + int vtblIndex; // for member functions, index into vtbl[] int naked; // !=0 if naked int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus = ILS.ILSuninitialized; + ILS inlineStatus; int inlineNest; // !=0 if nested inline int cantInterpret; // !=0 if cannot interpret function int semanticRun; // 1 semantic() run @@ -196,17 +202,52 @@ this.type = type; this.loc = loc; this.endloc = endloc; - + fthrows = null; + frequire = null; + fdrequire = null; + fdensure = null; + outId = null; + vresult = null; + returnLabel = null; + fensure = null; + fbody = null; + localsymtab = null; + vthis = null; + v_arguments = null; +version (IN_GCC) { + v_argptr = null; +} + parameters = null; + labtab = null; + overnext = null; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILS.ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = 0; +version (DMDV1) { + nestedFrameRef = 0; +} + fes = null; + introducing = 0; + tintro = null; /* The type given for "infer the return type" is a TypeFunction with * null for the return type. */ inferRetType = (type && type.nextOf() is null); - + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = null; + shidden = null; +version (DMDV2) { + builtin = BUILTINunknown; + tookAddressOf = 0; +} + foverrides = new FuncDeclarations(); closureVars = new Dsymbols(); - -version (DMDV2) { - builtin = BUILTIN.BUILTINunknown; -} } override Dsymbol syntaxCopy(Dsymbol s) @@ -551,6 +592,10 @@ } cd.vtbl.data[vi] = cast(void*)this; vtblIndex = vi; + + /* Remember which functions this overrides + */ + foverrides.push(cast(void*)fdv); /* This works by whenever this function is called, * it actually returns tintro, which gets dynamically @@ -597,9 +642,13 @@ default: { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; Type ti = null; + + /* Remember which functions this overrides + */ + foverrides.push(cast(void*)fdv); if (fdv.tintro) - ti = fdv.tintro; + ti = fdv.tintro; else if (!type.equals(fdv.type)) { /* Only need to have a tintro if the vptr @@ -727,6 +776,61 @@ } } } + + if (isVirtual()) + { + /* Rewrite contracts as nested functions, then call them. + * Doing it as nested functions means that overriding functions + * can call them. + */ + if (frequire) + { + /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + Loc loc = frequire.loc; + TypeFunction tf = new TypeFunction(null, Type.tvoid, 0, LINKd); + FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf); + fd.fbody = frequire; + Statement s1 = new DeclarationStatement(loc, fd); + Expression e = new CallExp(loc, new VarExp(loc, fd, 0), cast(Expressions)null); + Statement s2 = new ExpStatement(loc, e); + frequire = new CompoundStatement(loc, s1, s2); + fdrequire = fd; + } + + if (fensure) + { /* out (result) { ... } + * becomes: + * tret __ensure(ref tret result) { ... } + * __ensure(result); + */ + if (!outId && f.nextOf().toBasetype().ty != Tvoid) + outId = Id.result; // provide a default + + Loc loc = fensure.loc; + Arguments arguments = new Arguments(); + Argument a = null; + if (outId) + { + a = new Argument(STCref, f.nextOf(), outId, null); + arguments.push(cast(void*)a); + } + TypeFunction tf = new TypeFunction(arguments, Type.tvoid, 0, LINKd); + FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf); + fd.fbody = fensure; + Statement s1 = new DeclarationStatement(loc, fd); + Expression eresult = null; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression e = new CallExp(loc, new VarExp(loc, fd, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + fensure = new CompoundStatement(loc, s1, s2); + fdensure = fd; + } + } Ldone: /* Save scope for possible later use (if we need the @@ -790,6 +894,9 @@ error("can only throw classes, not %s", t.toChars()); } } + + frequire = mergeFrequire(frequire); + fensure = mergeFensure(fensure); if (fbody || frequire) { @@ -1328,27 +1435,29 @@ if (argptr) { // Initialize _argptr to point past non-variadic arg version (IN_GCC) { - // Handled in FuncDeclaration.toObjFile - v_argptr = argptr; - v_argptr.init = new VoidInitializer(loc); + // Handled in FuncDeclaration.toObjFile + v_argptr = argptr; + v_argptr.init = new VoidInitializer(loc); } else { - Expression e1; - Expression e; - Type t = argptr.type; - VarDeclaration p; - uint offset; - - e1 = new VarExp(Loc(0), argptr); - if (parameters && parameters.dim) - p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = cast(uint)p.type.size(); /// - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(Loc(0), p, offset); - e = new AssignExp(Loc(0), e1, e); - e.type = t; - a.push(cast(void*)new ExpStatement(Loc(0), e)); + Type t = argptr.type; + VarDeclaration p; + uint offset; + + Expression e1 = new VarExp(Loc(0), argptr); + if (parameters && parameters.dim) + p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + if (p.storage_class & STClazy) + // If the last parameter is lazy, it's the size of a delegate + offset = PTRSIZE * 2; + else + offset = cast(size_t)p.type.size(); + offset = (offset + 3) & ~3; // assume stack aligns on 4 + Expression e = new SymOffExp(Loc(0), p, offset); + e = new AssignExp(Loc(0), e1, e); + e.type = t; + a.push(cast(void*)new ExpStatement(Loc(0), e)); } } @@ -2767,6 +2876,99 @@ return true; } + /**************************************************** + * Merge into this function the 'in' contracts of all it overrides. + * 'in's are OR'd together, i.e. only one of them needs to pass. + */ + + Statement mergeFrequire(Statement sf) + { + /* Implementing this is done by having the overriding function call + * nested functions (the fdrequire functions) nested inside the overridden + * function. This requires that the stack layout of the calling function's + * parameters and 'this' pointer be in the same place (as the nested + * function refers to them). + * This is easy for the parameters, as they are all on the stack in the same + * place by definition, since it's an overriding function. The problem is + * getting the 'this' pointer in the same place, since it is a local variable. + * We did some hacks in the code generator to make this happen: + * 1. always generate exception handler frame, or at least leave space for it + * in the frame (Windows 32 SEH only) + * 2. always generate an EBP style frame + * 3. since 'this' is passed in a register that is subsequently copied into + * a stack local, allocate that local immediately following the exception + * handler block, so it is always at the same offset from EBP. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; + sf = fdv.mergeFrequire(sf); + if (fdv.frequire) + { + //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); + /* Make the call: + * try { __require(); } + * catch { frequire; } + */ + Expression eresult = null; + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + + if (sf) + { + Catch c = new Catch(loc, null, null, sf); + Array catches = new Array(); + catches.push(cast(void*)c); + sf = new TryCatchStatement(loc, s2, catches); + } + else + sf = s2; + } + } + return sf; + } + + /**************************************************** + * Merge into this function the 'out' contracts of all it overrides. + * 'out's are AND'd together, i.e. all of them need to pass. + */ + + Statement mergeFensure(Statement sf) + { + /* Same comments as for mergeFrequire(), except that we take care + * of generating a consistent reference to the 'result' local by + * explicitly passing 'result' to the nested function as a reference + * argument. + * This won't work for the 'this' parameter as it would require changing + * the semantic code for the nested function so that it looks on the parameter + * list for the 'this' pointer, something that would need an unknown amount + * of tweaking of various parts of the compiler that I'd rather leave alone. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; + sf = fdv.mergeFensure(sf); + if (fdv.fensure) + { + //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); + // Make the call: __ensure(result) + Expression eresult = null; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, 0), eresult); + Statement s2 = new ExpStatement(loc, e); + + if (sf) + { + sf = new CompoundStatement(fensure.loc, s2, sf); + } + else + sf = s2; + } + } + return sf; + } + static FuncDeclaration genCfunc(Type treturn, string name) { return genCfunc(treturn, Lexer.idPool(name)); @@ -2991,6 +3193,16 @@ s = func.toSymbol(); f = s.Sfunc; + +version (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 (isVirtual() && (fensure || frequire)) + f.Fflags3 |= F3.Ffakeeh; +} version (TARGET_OSX) { s.Sclass = SC.SCcomdat;