void DetectNullSafeArrayToPointer(BlockContainer container) { // Detect the following pattern: // ... // stloc V(ldloc S) // if (comp(ldloc S == ldnull)) br B_null_or_empty // br B_not_null // } // Block B_not_null { // if (conv i->i4 (ldlen(ldloc V))) br B_not_null_and_not_empty // br B_null_or_empty // } // Block B_not_null_and_not_empty { // stloc P(ldelema(ldloc V, ldc.i4 0, ...)) // br B_target // } // Block B_null_or_empty { // stloc P(conv i4->u(ldc.i4 0)) // br B_target // } // And convert the whole thing into: // ... // stloc P(array.to.pointer(V)) // br B_target bool modified = false; for (int i = 0; i < container.Blocks.Count; i++) { var block = container.Blocks[i]; if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock)) { context.Step("NullSafeArrayToPointerPattern", block); ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), null); if (p.StackType != StackType.Ref) { arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None); } block.Instructions[block.Instructions.Count - 2] = new StLoc(p, arrayToPointer) .WithILRange(block.Instructions[block.Instructions.Count - 2]); ((Branch)block.Instructions.Last()).TargetBlock = targetBlock; modified = true; } } if (modified) { container.Blocks.RemoveAll(b => b.IncomingEdgeCount == 0); // remove blocks made unreachable } }
void DetectNullSafeArrayToPointerOrCustomRefPin(BlockContainer container) { bool modified = false; for (int i = 0; i < container.Blocks.Count; i++) { var block = container.Blocks[i]; if (IsNullSafeArrayToPointerPattern(block, out ILVariable v, out ILVariable p, out Block targetBlock)) { context.Step("NullSafeArrayToPointerPattern", block); ILInstruction arrayToPointer = new GetPinnableReference(new LdLoc(v), null); if (p.StackType != StackType.Ref) { arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None); } block.Instructions[block.Instructions.Count - 2] = new StLoc(p, arrayToPointer) .WithILRange(block.Instructions[block.Instructions.Count - 2]); ((Branch)block.Instructions.Last()).TargetBlock = targetBlock; modified = true; }