Думая, что инструкция ldind не нужна для встроенных структур, а индексатор массива имеет доступ к измененным параметрам плохо? - PullRequest
0 голосов
/ 14 марта 2020

Пусть go для массива первым.

Код

void Do1(in int[] ints)
{
  inty[0] = 0;
}

void Do2(int[] ints)
{
  inty[0] = 0;
}

CIL

.method private hidebysig 
  instance void Do1 (
    [in] int32[]& inty
  ) cil managed 
{
  .param [1]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  // Method begins at RVA 0x2270
  // Code size 6 (0x6)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: ldind.ref
  IL_0002: ldc.i4.0
  IL_0003: ldc.i4.0
  IL_0004: stelem.i4
  IL_0005: ret
} // end of method DefensiveCopyTest::Do1

.method private hidebysig 
  instance void Do2 (
    int32[] inty
  ) cil managed 
{
  // Method begins at RVA 0x2277
  // Code size 5 (0x5)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: ldc.i4.0
  IL_0002: ldc.i4.0
  IL_0003: stelem.i4
  IL_0004: ret
} // end of method DefensiveCopyTest::Do2

In пункт Никогда не используйте изменяемые структуры, как в аргументе указано, что причина для защитной копии заключается в том, что средство доступа Get может изменять состояние объекта. Я полагаю, что это не радует доступ к индексатору массива.

Смотрите int.

Код

int Do1(in int num)
{
  var n = num;
  return n;
}

int Do2(int num)
{
  var n = num;
  return n;
}

CIL

.method private hidebysig 
  instance int32 Do1 (
    [in] int32& num
  ) cil managed 
{
  .param [1]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  // Method begins at RVA 0x227d
  // Code size 3 (0x3)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: ldind.i4
  IL_0002: ret
} // end of method DefensiveCopyTest::Do1

.method private hidebysig 
  instance int32 Do2 (
    int32 num
  ) cil managed 
{
  // Method begins at RVA 0x2281
  // Code size 2 (0x2)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: ret
} // end of method DefensiveCopyTest::Do2

Ситуация такая же. На этот раз ldind.i4 создает защитную копию. Снова доступ к. NET примитивам можно изменить их состояние?

Запрос сейчас

Это какая-то бюджетная функция или в этом случае есть причина делать защитные копии?

1 Ответ

1 голос
/ 14 марта 2020

Да, это так.

Давайте рассмотрим образец

ref readonly int Do1(in int num)
{
  var n = num;
  return ref num;
}

.method private hidebysig 
  instance int32& modreq([System.Runtime]System.Runtime.InteropServices.InAttribute) Do1 (
    [in] int32& num
  ) cil managed 
{
  .param [0]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  .param [1]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  // Method begins at RVA 0x227d
  // Code size 2 (0x2)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: ret
} // end of method DefensiveCopyTest::Do1

Поскольку нет необходимости распаковывать ссылку, нет Идентификатор инструкция.


Позвольте go для исчерпывающего ответа

Давайте посмотрим MS-подобный образец

void DoThingsWithPoint3D(in Point3D point1, in Point3D point2)
{
  double xDifference = point1.X - point2.X;
  double yDifference = point1.Y - point2.Y;
  double zDifference = point1.Z - point2.Z;
}

struct Point3D
{
  public int X { get; set; }
  public int Y { get; set; }
  public int Z { get; set; }
}

.method private hidebysig 
  instance void DoThingsWithPoint3D (
    [in] valuetype StaticLocalFunction.DefensiveCopyTest/Point3D& point1,
    [in] valuetype StaticLocalFunction.DefensiveCopyTest/Point3D& point2
  ) cil managed 
{
  .param [1]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  .param [2]
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
      01 00 00 00
    )
  // Method begins at RVA 0x22a0
  // Code size 43 (0x2b)
  .maxstack 8

  IL_0000: ldarg.1
  IL_0001: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
  IL_0006: pop
  IL_0007: ldarg.2
  IL_0008: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
  IL_000d: pop
  IL_000e: ldarg.1
  IL_000f: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
  IL_0014: pop
  IL_0015: ldarg.2
  IL_0016: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
  IL_001b: pop
  IL_001c: ldarg.1
  IL_001d: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
  IL_0022: pop
  IL_0023: ldarg.2
  IL_0024: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
  IL_0029: pop
  IL_002a: ret
} // end of method DefensiveCopyTest::DoThingsWithPoint3D

Защитная копия обеспечивается ldarg инструкция.

Доказательство

void DoThingsWithPoint3D(Point3D point1, Point3D point2)
{
  double xDifference = point1.X - point2.X;
  double yDifference = point1.Y - point2.Y;
  double zDifference = point1.Z - point2.Z;
}

.method private hidebysig 
  instance void DoThingsWithPoint3D (
    valuetype StaticLocalFunction.DefensiveCopyTest/Point3D point1,
    valuetype StaticLocalFunction.DefensiveCopyTest/Point3D point2
  ) cil managed 
{
  // Method begins at RVA 0x22cc
  // Code size 49 (0x31)
  .maxstack 8

  IL_0000: ldarga.s point1
  IL_0002: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
  IL_0007: pop
  IL_0008: ldarga.s point2
  IL_000a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
  IL_000f: pop
  IL_0010: ldarga.s point1
  IL_0012: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
  IL_0017: pop
  IL_0018: ldarga.s point2
  IL_001a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
  IL_001f: pop
  IL_0020: ldarga.s point1
  IL_0022: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
  IL_0027: pop
  IL_0028: ldarga.s point2
  IL_002a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
  IL_002f: pop
  IL_0030: ret
} // end of method DefensiveCopyTest::DoThingsWithPoint3D

Для чтения вызывается ldarga.s инструкция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...