static uint InsertStateGetAndUpdate(CFGContext ctx, ref int index, BlockKeyType type, ref CFGState currentState, CFGState?targetState) { var body = ctx.Graph.Body; if (type == BlockKeyType.Incremental) { // Incremental if (targetState == null) { // Randomly update and get state int updateId = ctx.Random.NextInt32(3); uint targetValue = ctx.Random.NextUInt32(); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(false, updateId, getId); var incr = currentState.GetIncrementalUpdate(updateId, targetValue); currentState.UpdateExplicit(updateId, targetValue); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); return(currentState.Get(getId)); } // Scan for updated state int[] stateIds = { 0, 1, 2, 3 }; ctx.Random.Shuffle(stateIds); int i = 0; uint getValue = 0; foreach (var stateId in stateIds) { // There must be at least one update&get if (currentState.Get(stateId) == targetState.Value.Get(stateId) && i != stateIds.Length - 1) { i++; continue; } uint targetValue = targetState.Value.Get(stateId); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(false, stateId, getId); var incr = currentState.GetIncrementalUpdate(stateId, targetValue); currentState.UpdateExplicit(stateId, targetValue); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); i++; if (i == stateIds.Length) { getValue = currentState.Get(getId); } else { body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop)); } } return(getValue); } else { // Explicit if (targetState == null) { // Create new exit state from random seed var seed = ctx.Random.NextUInt32(); currentState = new CFGState(seed); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Dup)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)seed)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor)); // Randomly get state int updateId = ctx.Random.NextInt32(3); uint targetValue = ctx.Random.NextUInt32(); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(false, updateId, getId); var incr = currentState.GetIncrementalUpdate(updateId, targetValue); currentState.UpdateExplicit(updateId, targetValue); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); return(currentState.Get(getId)); } else { // Scan for updated state int[] stateIds = { 0, 1, 2, 3 }; ctx.Random.Shuffle(stateIds); int i = 0; uint getValue = 0; foreach (var stateId in stateIds) { uint targetValue = targetState.Value.Get(stateId); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(true, stateId, getId); currentState.UpdateExplicit(stateId, targetValue); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue)); body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); i++; if (i == stateIds.Length) { getValue = targetState.Value.Get(getId); } else { body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop)); } } return(getValue); } } }
static void InsertEmptyStateUpdate(CFGContext ctx, ControlFlowBlock block) { var body = ctx.Graph.Body; var key = ctx.Keys[block.Id]; if (key.EntryState == key.ExitState) { return; } Instruction first = null; // Cannot use graph.IndexOf because instructions has been modified. int targetIndex = body.Instructions.IndexOf(block.Header); CFGState entry; if (!ctx.StatesMap.TryGetValue(key.EntryState, out entry)) { key.Type = BlockKeyType.Explicit; } if (key.Type == BlockKeyType.Incremental) { // Incremental CFGState exit; if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) { // Create new exit state // Update one of the entry states to be exit state exit = entry; int updateId = ctx.Random.NextInt32(3); uint targetValue = ctx.Random.NextUInt32(); exit.UpdateExplicit(updateId, targetValue); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(false, updateId, getId); var incr = entry.GetIncrementalUpdate(updateId, targetValue); body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); ctx.StatesMap[key.ExitState] = exit; } else { // Scan for updated state var headerIndex = targetIndex; for (int stateId = 0; stateId < 4; stateId++) { if (entry.Get(stateId) == exit.Get(stateId)) { continue; } uint targetValue = exit.Get(stateId); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(false, stateId, getId); var incr = entry.GetIncrementalUpdate(stateId, targetValue); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); } first = body.Instructions[headerIndex]; } } else { // Explicit CFGState exit; if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) { // Create new exit state from random seed var seed = ctx.Random.NextUInt32(); exit = new CFGState(seed); body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)seed)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor)); ctx.StatesMap[key.ExitState] = exit; } else { // Scan for updated state var headerIndex = targetIndex; for (int stateId = 0; stateId < 4; stateId++) { uint targetValue = exit.Get(stateId); int getId = ctx.Random.NextInt32(3); var fl = CFGState.EncodeFlag(true, stateId, getId); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); } first = body.Instructions[headerIndex]; } } ctx.Graph.Body.ReplaceReference(block.Header, first); }