From f5df8bb22c4547e85e481a30c6e5b7ec024c9d73 Mon Sep 17 00:00:00 2001 From: n8allan Date: Thu, 19 Jan 2017 09:27:37 -0700 Subject: [PATCH] Binary searched length cache and no superfluous cache clearing. LengthTo showed up as the main hot-spot on profiles of large method emissions. The replaced implementation would always start at the beginning in the event of a miss (even though length determination might have been done through a higher offset, and the cache was being cleared even in the most common event of a simply appended instruction. --- Sigil/Impl/BufferedILGenerator.cs | 150 +++++++++++++++--------------- 1 file changed, 73 insertions(+), 77 deletions(-) diff --git a/Sigil/Impl/BufferedILGenerator.cs b/Sigil/Impl/BufferedILGenerator.cs index 3121c9a..444e463 100644 --- a/Sigil/Impl/BufferedILGenerator.cs +++ b/Sigil/Impl/BufferedILGenerator.cs @@ -91,7 +91,60 @@ public string UnBuffer(ILGenerator il) return log.ToString(); } - private Dictionary LengthCache = new Dictionary(); + private IList LengthCacheEnds = new List(); + private IList LengthCacheOffsets = new List(); + + private int FindInCache(int value) + { + int startIndex = 0; + int endIndex = LengthCacheEnds.Count - 1; + + while (startIndex < endIndex) + { + var middleIndex = (startIndex + endIndex) / 2; + var compareResult = LengthCacheEnds[middleIndex].CompareTo(value); + + if (compareResult > 0) + { + endIndex = middleIndex - 1; + } + else if (compareResult < 0) + { + startIndex = middleIndex + 1; + } + else + { + return middleIndex; + } + } + + if (startIndex == endIndex) + { + var compareResult = LengthCacheEnds[startIndex].CompareTo(value); + + if (compareResult <= 0) + { + return startIndex; + } + else + { + int returnIndex = startIndex - 1; + + if (returnIndex < 0) + { + return -1; + } + else + { + return returnIndex; + } + } + } + else + { + return startIndex - 1; + } + } private int LengthTo(int end) { @@ -100,26 +153,29 @@ private int LengthTo(int end) return 0; } - int cached; - if (LengthCache.TryGetValue(end, out cached)) + var cacheIndex = FindInCache(end); + if (cacheIndex >= 0 && LengthCacheEnds[cacheIndex] == end) { - return cached; + return LengthCacheOffsets[cacheIndex]; } - int runningTotal = 0; + int runningTotal = cacheIndex >= 0 ? LengthCacheOffsets[cacheIndex] : 0; - for (var i = 0; i < end; i++) + for (var i = cacheIndex >= 0 ? LengthCacheEnds[cacheIndex] : 0; i < end; ++i) { - var s = InstructionSizes[i]; - - runningTotal += s(); - - LengthCache[i + 1] = runningTotal; + runningTotal += InstructionSizes[i](); } + var insertPoint = Math.Max(0, cacheIndex); + LengthCacheOffsets.Insert(insertPoint, runningTotal); + LengthCacheEnds.Insert(insertPoint, end); - cached = LengthCache[end]; + return runningTotal; + } - return cached; + private void ClearLengthCache() + { + LengthCacheOffsets.Clear(); + LengthCacheEnds.Clear(); } internal string[] Instructions(LinqList locals) @@ -222,7 +278,7 @@ public void Remove(int ix) throw new ArgumentOutOfRangeException("ix", "Expected value between 0 and " + Buffer.Count); } - LengthCache.Clear(); + ClearLengthCache(); InstructionSizes.RemoveAt(ix); @@ -240,7 +296,7 @@ public void Insert(int ix, OpCode op) throw new ArgumentOutOfRangeException("ix", "Expected value between 0 and " + Buffer.Count); } - LengthCache.Clear(); + ClearLengthCache(); InstructionSizes.Insert(ix, () => InstructionSize.Get(op)); @@ -279,8 +335,6 @@ public void Emit(OpCode op) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -309,8 +363,6 @@ public void Emit(OpCode op, byte b) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -339,8 +391,6 @@ public void Emit(OpCode op, short s) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -369,8 +419,6 @@ public void Emit(OpCode op, int i) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -405,8 +453,6 @@ public void Emit(OpCode op, uint ui) InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -428,8 +474,6 @@ public void Emit(OpCode op, long l) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -457,8 +501,6 @@ public void Emit(OpCode op, ulong ul) InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -480,8 +522,6 @@ public void Emit(OpCode op, float f) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -503,8 +543,6 @@ public void Emit(OpCode op, double d) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -525,8 +563,6 @@ public void Emit(OpCode op, MethodInfo method, IEnumerable parameterTypes) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -563,8 +599,6 @@ public void Emit(OpCode op, ConstructorInfo cons, IEnumerable parameterTyp { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -599,8 +633,6 @@ public void Emit(OpCode op, ConstructorInfo cons) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -622,8 +654,6 @@ public void Emit(OpCode op, Type type) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -645,8 +675,6 @@ public void Emit(OpCode op, FieldInfo field) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -668,8 +696,6 @@ public void Emit(OpCode op, string str) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -694,15 +720,13 @@ public void Emit(OpCode op, Sigil.Label label, out UpdateOpCodeDelegate update) update = newOpcode => { - LengthCache.Clear(); + ClearLengthCache(); localOp = newOpcode; }; InstructionSizes.Add(() => InstructionSize.Get(localOp)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -728,15 +752,13 @@ public void Emit(OpCode op, Sigil.Label[] labels, out UpdateOpCodeDelegate updat update = newOpcode => { - LengthCache.Clear(); + ClearLengthCache(); localOp = newOpcode; }; InstructionSizes.Add(() => InstructionSize.Get(localOp, labels)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -776,8 +798,6 @@ public void Emit(OpCode op, Sigil.Local local) { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -800,8 +820,6 @@ public void Emit(OpCode op, CallingConventions callConventions, Type returnType, { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -826,8 +844,6 @@ public void EmitCall(OpCode op, MethodInfo method, IEnumerable parameterTy { InstructionSizes.Add(() => InstructionSize.Get(op)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -869,8 +885,6 @@ public void EmitCalli(CallingConventions callingConvention, Type returnType, Typ { InstructionSizes.Add(() => InstructionSize.Get(OpCodes.Calli)); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -918,8 +932,6 @@ public DefineLabelDelegate BeginExceptionBlock() InstructionSizes.Add(() => InstructionSize.BeginExceptionBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -943,8 +955,6 @@ public void BeginCatchBlock(Type exception) { InstructionSizes.Add(() => InstructionSize.BeginCatchBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -966,8 +976,6 @@ public void EndExceptionBlock() { InstructionSizes.Add(() => InstructionSize.EndExceptionBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -989,8 +997,6 @@ public void EndCatchBlock() { InstructionSizes.Add(() => InstructionSize.EndCatchBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -1007,8 +1013,6 @@ public void BeginFinallyBlock() { InstructionSizes.Add(() => InstructionSize.BeginFinallyBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -1030,8 +1034,6 @@ public void EndFinallyBlock() { InstructionSizes.Add(() => InstructionSize.EndFinallyBlock()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -1067,8 +1069,6 @@ public DefineLabelDelegate DefineLabel() InstructionSizes.Add(() => InstructionSize.DefineLabel()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -1090,8 +1090,6 @@ public void MarkLabel(Sigil.Label label) { InstructionSizes.Add(() => InstructionSize.MarkLabel()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly, log) => { @@ -1134,8 +1132,6 @@ public DeclareLocallDelegate DeclareLocal(Type type) InstructionSizes.Add(() => InstructionSize.DeclareLocal()); - LengthCache.Clear(); - Buffer.Add( (il, logOnly,log) => {