namespace FlexSwitch6 { using System; using Benchmark; /* Differences with FlexSwitch5: arguments across links are not stored into a preallocated InputArgs, but into a bunch of global arrays (one for each primitive type + one for objects). The arrays can grow is more space is needed. Since the values inside the arrays are copied back to local variables as soon as we enter the target block, there is no risk of race conditions (in case of single threaded application) Jump between basic block inside cases of flexswitches ----------------------------------------------------- Each basic block in a function and in its "childs" (i.e. the cases generated by flexswitches) is numbered with an unique ID. Arguments across non-local links are passed by passing an instance of the InputArgs class; this class contains enough fields to be able to store every possible set of inputargs needed by the function. At the beginning of the function, InputArgs is instantiated, and the object args is passed around when calling into flexswitches. Before calling a flexswitch case, you need to setup args accordingly to the inputargs expected by the block you are jumping in. The same must be done before returning from a flexswitch case; moreover, the return value of the flexswitch case is an int which specifies the ID of the block we want to jump to. Whenever we want to do a non-local jump (e.g., after the call to a flexswitch case), we set args as the expected inputargs and the jumpto variable to the ID of the target block, then you jump to "dispatch_jump". If the target block happens to be inside a flexswitch case, "dispatch_jump" will take care of locating the right delegate and call it passing the ID of the block as the first argument (XXX: not implemented yet). */ delegate int SwitchCaseFunc(int block); delegate int SwitchDefaultCase(FlexSwitch obj, object value); // this class will be automatically generated by the JIT backend class InputArgs { public static int[] ints = new int[10]; // growable } class FlexSwitch { public int numcases = 0; object[] values = new object[2]; SwitchCaseFunc[] funcs = new SwitchCaseFunc[2]; public SwitchDefaultCase defaultcase; private void grow() { int newsize = funcs.Length * 2; object[] newvalues = new object[newsize]; Array.Copy(values, newvalues, values.Length); values = newvalues; SwitchCaseFunc[] newfuncs = new SwitchCaseFunc[newsize]; Array.Copy(funcs, newfuncs, funcs.Length); funcs = newfuncs; } public void addcase(object v, SwitchCaseFunc c) { if (numcases >= values.Length) grow(); values[numcases] = v; funcs[numcases] = c; numcases++; } public int execute(object v) { for(int i=0; i= bytecode.Length) return accumulator; goto fetch; // end main loop dispatch_jump: if (jumpto == FETCH) goto fetch; else if (jumpto == EXEC) goto exec; else if (jumpto == NEXT) goto next; else throw new Exception("error in dispatch_jump"); } } }