private static void DoBinarySearch(MethodJumpEmittingContext context, int l, int r) { var il = context.il; if (l > r) { il.Br(context.retNullLabel); return; } if (r - l + 1 <= 3) { // just bunch of ifs for (; l <= r; l++) { il.Ldarg(1); // stack: [key] il.Ldarg(0); // stack: [key, this] il.Ldfld(context.context.keys[l]); // stack: [key, this.keys[l]] var nextLabel = il.DefineLabel("next"); il.Bne_Un(nextLabel); // if(key != this.keys[l]) goto next; stack: [] il.Ldarg(0); // stack: [this] il.Ldfld(context.context.values[l]); // stack: [this.values[l]] il.Ret(); il.MarkLabel(nextLabel); } il.Br(context.retNullLabel); } else { int m = (l + r) / 2; il.Ldarg(1); // stack: [key] il.Ldarg(0); // stack: [key, this] il.Ldfld(context.context.keys[m]); // stack: [key, this.keys[m]] var nextLabel = il.DefineLabel("next"); il.Bne_Un(nextLabel); // if(key != this.keys[m]) goto next; stack: [] il.Ldarg(0); // stack: [this] il.Ldfld(context.context.values[m]); // stack: [this.values[m]] il.Ret(); il.MarkLabel(nextLabel); il.Ldarg(1); // stack: [key] il.Ldarg(0); // stack: [key, this] il.Ldfld(context.context.keys[m]); // stack: [key, this.keys[m]] var goLeftLabel = il.DefineLabel("goLeft"); il.Blt(goLeftLabel, false); // if(key < this.keys[m]]) goto goLeft; stack: [] DoBinarySearch(context, m + 1, r); il.MarkLabel(goLeftLabel); DoBinarySearch(context, l, m - 1); } }
private static void BuildJump(TypeBuilder typeBuilder, int n, Context context) { var method = typeBuilder.DefineMethod("Jump", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.HasThis, typeof(MethodCallNode), new[] { typeof(int) }); using (var il = new GroboIL(method)) { var retNullLabel = il.DefineLabel("retNull"); var emittingContext = new MethodJumpEmittingContext { context = context, il = il, retNullLabel = retNullLabel }; DoBinarySearch(emittingContext, 0, n - 1); il.MarkLabel(retNullLabel); il.Ldnull(); il.Ret(); } typeBuilder.DefineMethodOverride(method, typeof(MethodCallNodeEdges).GetMethod(method.Name, BindingFlags.Public | BindingFlags.Instance)); }