private IEnumerable <ProgramState> ProcessSwt(ILInstruction instruction, ProgramState next) { var result = new List <ProgramState>(); var symbolicTableSlot = next.Stack.Pop(); var symbolicValue = next.Stack.Pop(); instruction.Dependencies.AddOrMerge(0, symbolicTableSlot); instruction.Dependencies.AddOrMerge(1, symbolicValue); var annotation = new JumpAnnotation { InferredPopCount = instruction.Dependencies.Count, InferredPushCount = 0 }; ulong tableAddress = symbolicTableSlot.InferStackValue().U8; var reader = new MemoryStreamReader(KoiStream.Data); reader.Position = (long)tableAddress - 2; ushort count = reader.ReadUInt16(); for (int i = 0; i < count; i++) { int relativeOffset = reader.ReadInt32(); ulong nextIp = (ulong)((long)next.IP + relativeOffset); Logger.Debug(Tag, $"Inferred edge IL_{instruction.Offset:X4} -> IL_{nextIp:X4}"); var caseState = next.Copy(); caseState.IP = nextIp; result.Add(caseState); annotation.InferredJumpTargets.Add(nextIp); } result.Add(next); instruction.Annotation = annotation; return(result); }
private void ParseSection(SubChunk section, ReadOnlyMemory <byte> data) { var reader = new MemoryStreamReader(data); var version = reader.ReadByte(); if (version != 8) { throw new Exception("Wrong chunk version"); } var storageSize = reader.ReadByte(); for (int storage = 0; storage < storageSize; storage++) { byte paletteAndFlag = (byte)reader.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; if (isRuntime) { throw new Exception("Can't use runtime for persistent storage."); } int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096d / blocksPerWord); long blockIndex = reader.Position; reader.Position += wordCount * 4; int paletteSize = reader.ReadInt32(); var palette = new Dictionary <int, int>(); for (int j = 0; j < paletteSize; j++) { var file = new NbtFile { BigEndian = false, UseVarInt = false }; file.LoadFromStream(reader, NbtCompression.None); var tag = (NbtCompound)file.RootTag; Block block = BlockFactory.GetBlockByName(tag["name"].StringValue); if (block != null && block.GetType() != typeof(Block) && !(block is Air)) { List <IBlockState> blockState = ReadBlockState(tag); block.SetState(blockState); } else { block = new Air(); } palette.Add(j, block.GetRuntimeId()); } long nextStore = reader.Position; reader.Position = blockIndex; int position = 0; for (int wordIdx = 0; wordIdx < wordCount; wordIdx++) { uint word = reader.ReadUInt32(); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; // padding bytes } int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state > palette.Count) { Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}"); } if (storage == 0) { section.SetBlockByRuntimeId(x, y, z, palette[state]); } else { section.SetLoggedBlockByRuntimeId(x, y, z, palette[state]); } position++; } } reader.Position = nextStore; } }