private static void MarkReachableFromSwitch(ArrayBuilder <BasicBlock> reachableBlocks, BasicBlock block) { SwitchBlock switchBlock = (SwitchBlock)block; ArrayBuilder <BasicBlock> blockBuilder = ArrayBuilder <BasicBlock> .GetInstance(); switchBlock.GetBranchBlocks(blockBuilder); foreach (BasicBlock targetBlock in blockBuilder) { PushReachableBlockToProcess(reachableBlocks, targetBlock); } blockBuilder.Free(); }
private void RealizeBlocks() { // drop dead code. // We do not want to deal with unreachable code even when not optimizing. // sometimes dead code may have subtle verification violations // for example illegal fall-through in unreachable code is still illegal, // but compiler will not enforce returning from dead code. // it is easier to just remove dead code than make sure it is all valid MarkReachableBlocks(); RewriteSpecialBlocks(); DropUnreachableBlocks(); if (_optimizations == OptimizationLevel.Release && OptimizeLabels()) { // redo unreachable code elimination if some labels were optimized // as that could result in more dead code. MarkAllBlocksUnreachable(); MarkReachableBlocks(); DropUnreachableBlocks(); } // some gotos must become leaves RewriteBranchesAcrossExceptionHandlers(); // now we can compute block offsets and adjust branches while (ComputeOffsetsAndAdjustBranches()) { // if branches were optimized, we may have more unreachable code // redo unreachable code elimination and if anything was dropped redo adjusting. MarkAllBlocksUnreachable(); MarkReachableBlocks(); if (!DropUnreachableBlocks()) { // nothing was dropped, we are done adjusting break; } } // Now linearize everything with computed offsets. Cci.PooledBlobBuilder writer = Cci.PooledBlobBuilder.GetInstance(); for (BasicBlock block = leaderBlock; block != null; block = block.NextBlock) { // If the block has any IL markers, we can calculate their real IL offsets now int blockFirstMarker = block.FirstILMarker; if (blockFirstMarker >= 0) { int blockLastMarker = block.LastILMarker; Debug.Assert(blockLastMarker >= blockFirstMarker); for (int i = blockFirstMarker; i <= blockLastMarker; i++) { int blockOffset = _allocatedILMarkers[i].BlockOffset; int absoluteOffset = writer.Count + blockOffset; _allocatedILMarkers[i] = new ILMarker() { BlockOffset = blockOffset, AbsoluteOffset = absoluteOffset }; } } block.RegularInstructions?.WriteContentTo(writer); switch (block.BranchCode) { case ILOpCode.Nop: break; case ILOpCode.Switch: // switch (N, t1, t2... tN) // IL ==> ILOpCode.Switch < unsigned int32 > < int32 >... < int32 > WriteOpCode(writer, ILOpCode.Switch); SwitchBlock switchBlock = (SwitchBlock)block; writer.WriteUInt32(switchBlock.BranchesCount); int switchBlockEnd = switchBlock.Start + switchBlock.TotalSize; ArrayBuilder <BasicBlock> blockBuilder = ArrayBuilder <BasicBlock> .GetInstance(); switchBlock.GetBranchBlocks(blockBuilder); foreach (BasicBlock branchBlock in blockBuilder) { writer.WriteInt32(branchBlock.Start - switchBlockEnd); } blockBuilder.Free(); break; default: WriteOpCode(writer, block.BranchCode); if (block.BranchLabel != null) { int target = block.BranchBlock.Start; int curBlockEnd = block.Start + block.TotalSize; int offset = target - curBlockEnd; if (block.BranchCode.GetBranchOperandSize() == 1) { sbyte btOffset = (sbyte)offset; Debug.Assert(btOffset == offset); writer.WriteSByte(btOffset); } else { writer.WriteInt32(offset); } } break; } } this.RealizedIL = writer.ToImmutableArray(); writer.Free(); RealizeSequencePoints(); this.RealizedExceptionHandlers = _scopeManager.GetExceptionHandlerRegions(); }