/* * Turn a function call into the corresponding GFunctionInterpreted. * This applies recursively on all the the call sub-tree. */ internal static GFunctionInterpreted Add(CCFunctionInterpreted cfi) { GFunctionInterpreted ngf = new GFunctionInterpreted(cfi); /* * Find the GFunction already existing for this function. */ SortedSet <GFunctionInterpreted> ss; if (!ALL.TryGetValue(cfi.fi, out ss)) { ss = new SortedSet <GFunctionInterpreted>(); ss.Add(ngf); ALL[cfi.fi] = ss; return(ngf); } /* * If the new function can be merged into any of the * existing GFunction, do it; otherwise, add it as a * new GFunction. */ foreach (GFunctionInterpreted gf in ss) { if (gf.Merge(ngf)) { return(gf); } } ss.Add(ngf); return(ngf); }
internal static CCNodeEntry EnterFunction(FunctionInterpreted fi, CCStack stack, CCNodeEntry parent, CCNode next) { if (Compiler.PrintFunctions != null) { fi.Print(Compiler.PrintFunctions, 1); } CCLocals locals = new CCLocals(fi.numLocalFieldsCoalesced); CCFunctionInterpreted cfi = new CCFunctionInterpreted(fi, next); CCNodeEntry node = new CCNodeEntry(parent, cfi); cfi.SetNode(0, node); node.MergeStack(stack); node.MergeLocals(locals); /* * All instances allocated locally by this function must * have instantiable types. */ foreach (XType xt in fi.localEmbedTypes) { xt.Close(); } /* * Infinite recursion detection: if the same function is * already present several times in the ancestry, * complains. (TODO: make the threshold configurable) */ int rc = 0; for (CCNodeEntry e = parent; e != null; e = e.parent) { if (e.cfi.fi == fi) { if (++rc >= 5) { throw new Exception(string.Format("possible infinite recursion on function {0}", fi.DebugName)); } } } return(node); }
internal CCNodeEntry(CCNodeEntry parent, CCFunctionInterpreted cfi) : base(cfi, 0) { this.parent = parent; }
internal CCNodeOpcode(CCFunctionInterpreted cfi, int addr) : base() { this.cfi = cfi; this.addr = addr; }
GFunctionInterpreted(CCFunctionInterpreted cfi) : base(cfi.fi) { this.fi = cfi.fi; /* * Specialize opcodes. In this step: * * - For each source opcode, we create an appropriate GOp * instance. Type specialization for local fields * happens here. * * - Unreachable opcodes (whose entry stack is null) yield * a GOpZero. */ List <GOp> specOps = new List <GOp>(); int srcLen = cfi.nodes.Length; for (int i = 0; i < srcLen; i++) { GOp g = cfi.ToGOp(i); if (g == null) { throw new Exception("NYI (GOp)"); } specOps.Add(g); } spec = specOps.ToArray(); AdjustJumps(); /* * Compute local frame elements: * * - For local fields, only putlocal and putlocalindexed * matter; we check that each local has a single storage * type. * * - For local instances, we use reflocal and * reflocalindexed. */ frame = new GOpFrame(this); for (int i = 0; i < spec.Length; i++) { var pl = spec[i] as GOpPutLocal; if (pl != null) { frame.AddLocalVariable(pl.off, pl.ltype); } var pli = spec[i] as GOpPutLocalIndexed; if (pli != null) { frame.AddLocalVariableArray( pli.off, pli.len, pli.ltype); } var rl = spec[i] as GOpRefLocal; if (rl != null) { frame.AddLocalInstance(rl.off, rl.ltype); } var rli = spec[i] as GOpRefLocalIndexed; if (rli != null) { frame.AddLocalInstanceArray( rli.off, rli.len, rli.ltype); } } }