Нема описа
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

031-Pointers.cs 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. using Unity.Burst;
  6. using Unity.Collections;
  7. using Unity.Collections.LowLevel.Unsafe;
  8. using Unity.Jobs;
  9. using Unity.Mathematics;
  10. using UnityBenchShared;
  11. namespace Burst.Compiler.IL.Tests
  12. {
  13. internal class Pointers
  14. {
  15. #if UNITY_2019_1_OR_NEWER
  16. [TestCompiler(1)]
  17. [TestCompiler(4)]
  18. [TestCompiler(5)]
  19. public static int CheckAddressOf(int a)
  20. {
  21. var value = new MyIntValue(a);
  22. ref int intValue = ref value.GetValuePtr();
  23. return intValue * 10 + 1;
  24. }
  25. public struct MyIntValue
  26. {
  27. public MyIntValue(int value)
  28. {
  29. Value = value;
  30. }
  31. public int Value;
  32. public unsafe ref int GetValuePtr()
  33. {
  34. fixed (void* ptr = &this)
  35. {
  36. return ref *(int*) ptr;
  37. }
  38. }
  39. }
  40. #endif
  41. [TestCompiler(0, MyCastEnum.Value2)]
  42. [TestCompiler(1, MyCastEnum.Value0)]
  43. [TestCompiler(2, MyCastEnum.Value3)]
  44. public static unsafe MyCastEnum PointerCastEnum(int value, MyCastEnum newValue)
  45. {
  46. var ptvalue = new IntPtr(&value);
  47. var pEnum = (MyCastEnum*) ptvalue;
  48. *pEnum = newValue;
  49. return *pEnum;
  50. }
  51. [TestCompiler(0, 0)]
  52. [TestCompiler(0, 1)]
  53. [TestCompiler(1, 0)]
  54. public static unsafe bool PointerCompare(IntPtr a, IntPtr b)
  55. {
  56. return a == b;
  57. }
  58. [TestCompiler(0)]
  59. [TestCompiler(1)]
  60. [TestCompiler(2)]
  61. public static unsafe bool RawPointerCompare(IntPtr value)
  62. {
  63. return (void*)value == (void*)1;
  64. }
  65. [TestCompiler(0)]
  66. [TestCompiler(1)]
  67. [TestCompiler(42424242)]
  68. public static unsafe int PointerHash(IntPtr value)
  69. {
  70. return value.GetHashCode();
  71. }
  72. [TestCompiler(0)]
  73. [TestCompiler(1)]
  74. [TestCompiler(42424242)]
  75. public static unsafe IntPtr PointerToPointer(IntPtr value)
  76. {
  77. return new IntPtr(value.ToPointer());
  78. }
  79. [TestCompiler(0, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MethodNotSupported)]
  80. public static unsafe int PointerToString(IntPtr value)
  81. {
  82. return value.ToString().Length;
  83. }
  84. [TestCompiler(1)]
  85. [TestCompiler(255)]
  86. [TestCompiler(12351235)]
  87. public static unsafe int PointerAdd(int a)
  88. {
  89. var pA = (byte*)&a;
  90. var pDest = pA + 3;
  91. *pDest = (byte)a;
  92. return a;
  93. }
  94. [TestCompiler(1)]
  95. [TestCompiler(255)]
  96. [TestCompiler(12351235)]
  97. public static unsafe int PointerSub(int a)
  98. {
  99. var pA = (byte*)&a;
  100. var pDest = pA + 3;
  101. *(pDest - 1) = (byte)a;
  102. return a;
  103. }
  104. [TestCompiler]
  105. public static unsafe int PointerPointerSub()
  106. {
  107. var value = new StructForPointerPointerSub();
  108. int* pa = &value.A;
  109. int* pb = &value.B;
  110. var auto = (pb - pa);
  111. return (int)auto;
  112. }
  113. [TestCompiler]
  114. public static unsafe int WhileWithPointer()
  115. {
  116. var check = new CheckPointers { X = 1, Y = 2, Z = 3, W = 4 };
  117. int* pstart = &check.X;
  118. int* pend = &check.W;
  119. int result = 0;
  120. while (pstart <= pend)
  121. {
  122. result += *pstart;
  123. pstart++;
  124. }
  125. return result;
  126. }
  127. struct StructForPointerPointerSub
  128. {
  129. public int A;
  130. public int B;
  131. }
  132. [TestCompiler(1)]
  133. [TestCompiler(255)]
  134. [TestCompiler(12351235)]
  135. public static IntPtr IntPtrConstructor(int a)
  136. {
  137. return new IntPtr(a);
  138. }
  139. [TestCompiler(1U)]
  140. [TestCompiler(255U)]
  141. [TestCompiler(12351235U)]
  142. public static UIntPtr UIntPtrConstructor(uint a)
  143. {
  144. return new UIntPtr(a);
  145. }
  146. [TestCompiler(1)]
  147. [TestCompiler(255)]
  148. [TestCompiler(12351235)]
  149. public static int IntPtrToInt32(int a)
  150. {
  151. return new IntPtr(a).ToInt32();
  152. }
  153. [TestCompiler(1)]
  154. [TestCompiler(255)]
  155. [TestCompiler(12351235)]
  156. public static long IntPtrToInt64(int a)
  157. {
  158. return new IntPtr(a).ToInt64();
  159. }
  160. [TestCompiler(OverrideOn32BitNative = 4)]
  161. public static int IntPtrSize()
  162. {
  163. return IntPtr.Size;
  164. }
  165. // asserted in IntPtrProcessor
  166. [TestCompiler(OverrideOn32BitNative = true)]
  167. public static bool IntPtrSizeCompared()
  168. {
  169. return IntPtr.Size == 4;
  170. }
  171. [TestCompiler]
  172. public static IntPtr IntPtrZero()
  173. {
  174. return IntPtr.Zero;
  175. }
  176. [TestCompiler(1)]
  177. [TestCompiler(5)]
  178. public static IntPtr IntPtrAdd(IntPtr a)
  179. {
  180. return IntPtr.Add(a, 1);
  181. }
  182. [TestCompiler(1)]
  183. [TestCompiler(5)]
  184. public static IntPtr IntPtrAdd2(IntPtr a)
  185. {
  186. return a + 1;
  187. }
  188. [TestCompiler(1)]
  189. [TestCompiler(5)]
  190. public static IntPtr IntPtrSub(IntPtr a)
  191. {
  192. return IntPtr.Subtract(a, 1);
  193. }
  194. [TestCompiler(1)]
  195. [TestCompiler(5)]
  196. public static IntPtr IntPtrSub2(IntPtr a)
  197. {
  198. return a - 1;
  199. }
  200. [TestCompiler]
  201. public static UIntPtr UIntPtrZero()
  202. {
  203. return UIntPtr.Zero;
  204. }
  205. [TestCompiler(1U)]
  206. [TestCompiler(5U)]
  207. public static UIntPtr UIntPtrAdd(UIntPtr a)
  208. {
  209. return UIntPtr.Add(a, 1);
  210. }
  211. [TestCompiler(1U)]
  212. [TestCompiler(5U)]
  213. public static UIntPtr UIntPtrSubstract(UIntPtr a)
  214. {
  215. return UIntPtr.Subtract(a, 1);
  216. }
  217. [TestCompiler(1)]
  218. public static unsafe int PointerAccess(int a)
  219. {
  220. var value = a;
  221. var pValue = &value;
  222. pValue[0] = a + 5;
  223. return value;
  224. }
  225. [TestCompiler(0)] // Keep it at 0 only!
  226. public static unsafe int PointerAccess2(int a)
  227. {
  228. int value = 15;
  229. var pValue = &value;
  230. pValue[a] = value + 5;
  231. return value;
  232. }
  233. [TestCompiler(0)] // Keep it at 0 only!
  234. public static unsafe float PointerAccess3(int a)
  235. {
  236. float value = 15.0f;
  237. var pValue = &value;
  238. pValue[a] = value + 5.0f;
  239. return value;
  240. }
  241. [TestCompiler(0)]
  242. public static unsafe int PointerCompareViaInt(int a)
  243. {
  244. int b;
  245. if (&a == &b)
  246. return 1;
  247. else
  248. return 0;
  249. }
  250. [TestCompiler(0)]
  251. public static unsafe int IntPtrCompare(int a)
  252. {
  253. int b;
  254. IntPtr aPtr = (IntPtr)(&a);
  255. IntPtr bPtr = (IntPtr)(&b);
  256. if (aPtr == bPtr)
  257. return 1;
  258. else
  259. return 0;
  260. }
  261. [TestCompiler(typeof(IntPtrZeroProvider), 1)]
  262. [TestCompiler(typeof(IntPtrOneProvider), 2)]
  263. public static unsafe int UnsafeCompare(int* a, int b)
  264. {
  265. if (a == null)
  266. {
  267. return 1 + b;
  268. }
  269. return 2 + b;
  270. }
  271. unsafe struct NativeQueueBlockHeader
  272. {
  273. #pragma warning disable 0649
  274. public byte* nextBlock;
  275. public int itemsInBlock;
  276. #pragma warning restore 0649
  277. }
  278. [TestCompiler]
  279. public static unsafe void PointerCastWithStruct()
  280. {
  281. byte* currentWriteBlock = null;
  282. if (currentWriteBlock != null && ((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock == 100)
  283. {
  284. ((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock = 5;
  285. }
  286. }
  287. private class IntPtrZeroProvider : IArgumentProvider
  288. {
  289. public object Value => IntPtr.Zero;
  290. }
  291. private class IntPtrOneProvider : IArgumentProvider
  292. {
  293. public object Value => new IntPtr(1);
  294. }
  295. [TestCompiler]
  296. public static unsafe int FixedField()
  297. {
  298. var fixedStruct = new MyStructWithFixed();
  299. fixedStruct.Values[0] = 1;
  300. fixedStruct.Values[1] = 2;
  301. fixedStruct.Values[2] = 3;
  302. fixedStruct.Values[9] = 9;
  303. int result = 0;
  304. for (int i = 0; i < 10; i++)
  305. {
  306. result += fixedStruct.Values[i];
  307. }
  308. return result;
  309. }
  310. [TestCompiler(typeof(MyStructWithFixedProvider), 1)]
  311. //[TestCompiler(typeof(MyStructWithFixedProvider), 2)]
  312. public static unsafe int FixedFieldViaPointer(ref MyStructWithFixed fixedStruct, int i)
  313. {
  314. fixed (MyStructWithFixed* check = &fixedStruct)
  315. {
  316. int* data = check->Values;
  317. return data[i];
  318. }
  319. }
  320. [TestCompiler(typeof(MyStructWithFixedProvider))]
  321. public static unsafe int FixedInt32AndRefInt32(ref MyStructWithFixed fixedStruct)
  322. {
  323. fixed (int* data = &fixedStruct.Value)
  324. {
  325. // We do a call to ProcessInt after with a ref int
  326. // to check that we don't collide with the PinnedType introduced by the previous
  327. // fixed statement
  328. ProcessInt(ref *data);
  329. }
  330. return fixedStruct.Value;
  331. }
  332. private static void ProcessInt(ref int value)
  333. {
  334. value += 5;
  335. }
  336. public unsafe struct ConditionalTestStruct
  337. {
  338. public void* a;
  339. public void* b;
  340. }
  341. public unsafe struct PointerConditional : IJob, IDisposable
  342. {
  343. public ConditionalTestStruct* t;
  344. public void Execute()
  345. {
  346. t->b = t->a != null ? t->a : null;
  347. }
  348. public struct Provider : IArgumentProvider
  349. {
  350. public object Value
  351. {
  352. get
  353. {
  354. var value = new PointerConditional();
  355. value.t = (ConditionalTestStruct*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf<ConditionalTestStruct>(), 4, Allocator.Persistent);
  356. value.t->a = (void*)0x12345678;
  357. value.t->b = null;
  358. return value;
  359. }
  360. }
  361. }
  362. public void Dispose()
  363. {
  364. UnsafeUtility.Free(t, Allocator.Persistent);
  365. }
  366. }
  367. [TestCompiler(typeof(PointerConditional.Provider))]
  368. public static unsafe bool TestConditionalPointer([NoAlias] ref PointerConditional job)
  369. {
  370. job.Execute();
  371. return job.t->a == job.t->b;
  372. }
  373. #if BURST_TESTS_ONLY
  374. [TestCompiler]
  375. public static int TestFieldOffset()
  376. {
  377. var t = default(StructWithFields);
  378. return (int)Unsafe.ByteOffset(ref Unsafe.As<int, bool>(ref t.a), ref t.d);
  379. }
  380. #endif
  381. public struct StructWithFields
  382. {
  383. public int a;
  384. public int b;
  385. public bool c;
  386. public bool d;
  387. public bool e;
  388. public bool f;
  389. }
  390. public unsafe struct MyStructWithFixed
  391. {
  392. public fixed int Values[10];
  393. public int Value;
  394. }
  395. private struct MyStructWithFixedProvider : IArgumentProvider
  396. {
  397. public unsafe object Value
  398. {
  399. get
  400. {
  401. var field = new MyStructWithFixed();
  402. for (int i = 0; i < 10; i++)
  403. {
  404. field.Values[i] = (i + 1) * 5;
  405. }
  406. field.Value = 1235;
  407. return field;
  408. }
  409. }
  410. }
  411. [TestCompiler(0)]
  412. public static unsafe void TestCellVisibleInternal(int length)
  413. {
  414. int3* cellVisibleRequest = (int3*)0;
  415. bool*cellVisibleResult = (bool*)0;
  416. int3* visibleCells = (int3*)0;
  417. IsCellVisibleInternal(cellVisibleRequest, cellVisibleResult, visibleCells, length, length);
  418. }
  419. static unsafe void IsCellVisibleInternal(int3* cellVisibleRequest, bool* cellVisibleResult, int3* visibleCells, int requestLength, int visibleCellsLength)
  420. {
  421. for (int r = 0; r < requestLength; r++)
  422. {
  423. cellVisibleResult[r] = false;
  424. for (int i = 0; i < visibleCellsLength; i++)
  425. {
  426. if (visibleCells[i].x == cellVisibleRequest[r].x && visibleCells[i].y == cellVisibleRequest[r].y && visibleCells[i].z == cellVisibleRequest[r].z)
  427. {
  428. cellVisibleResult[r] = true;
  429. break;
  430. }
  431. }
  432. }
  433. }
  434. public enum MyCastEnum
  435. {
  436. Value0 = 0,
  437. Value1 = 1,
  438. Value2 = 2,
  439. Value3 = 3,
  440. }
  441. public struct CheckPointers
  442. {
  443. public int X;
  444. public int Y;
  445. public int Z;
  446. public int W;
  447. }
  448. // From https://github.com/Unity-Technologies/ECSJobDemos/issues/244
  449. [TestCompiler]
  450. public static unsafe int InitialiseViaCastedPointer()
  451. {
  452. int value = 0;
  453. void* ptr = &value;
  454. byte* asBytePtr = (byte*)ptr;
  455. ((int*)asBytePtr)[0] = -1;
  456. return value;
  457. }
  458. [TestCompiler(1)]
  459. public static unsafe int PointerWriteArg(int a)
  460. {
  461. return (int)TestPointerAndGeneric<float>((int*) a);
  462. }
  463. private static unsafe int* TestPointerAndGeneric<T>(int* p) where T : struct
  464. {
  465. p = (int*)(IntPtr)26;
  466. return p;
  467. }
  468. [TestCompiler(ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
  469. public static void TestBlobAssetReferenceData()
  470. {
  471. var blob = new BlobAssetReferenceData(IntPtr.Zero);
  472. blob.Validate();
  473. }
  474. [StructLayout(LayoutKind.Explicit, Size = 16)]
  475. internal unsafe struct BlobAssetHeader
  476. {
  477. [FieldOffset(0)] public void* ValidationPtr;
  478. [FieldOffset(8)] public int Length;
  479. [FieldOffset(12)] public Allocator Allocator;
  480. }
  481. internal unsafe struct BlobAssetReferenceData
  482. {
  483. [NativeDisableUnsafePtrRestriction]
  484. public byte* _ptr;
  485. public BlobAssetReferenceData(IntPtr zero)
  486. {
  487. _ptr = (byte*)zero;
  488. }
  489. internal BlobAssetHeader* Header => ((BlobAssetHeader*)_ptr) - 1;
  490. public void Validate()
  491. {
  492. if (_ptr != null)
  493. if (Header->ValidationPtr != _ptr)
  494. throw new InvalidOperationException("The BlobAssetReference is not valid. Likely it has already been unloaded or released");
  495. }
  496. }
  497. internal unsafe struct StackAllocCheck
  498. {
  499. public int* ptr;
  500. [MethodImpl(MethodImplOptions.NoInlining)]
  501. public void AddToPtr(int* otherPtr)
  502. {
  503. *otherPtr = 42;
  504. *ptr += 1;
  505. *ptr += *otherPtr;
  506. }
  507. public class Provider : IArgumentProvider
  508. {
  509. public object Value => new StackAllocCheck();
  510. }
  511. }
  512. [TestCompiler(typeof(StackAllocCheck.Provider))]
  513. public static unsafe bool StackAllocAliasCheck([NoAlias] ref StackAllocCheck stackAllocCheck)
  514. {
  515. int* ptr = stackalloc int[1];
  516. *ptr = 13;
  517. stackAllocCheck.ptr = ptr;
  518. stackAllocCheck.AddToPtr(ptr);
  519. if (*ptr != 86)
  520. {
  521. return false;
  522. }
  523. *stackAllocCheck.ptr = -4;
  524. *ptr += 1;
  525. *ptr += *stackAllocCheck.ptr;
  526. if (*ptr != -6)
  527. {
  528. return false;
  529. }
  530. return true;
  531. }
  532. [TestCompiler(1)]
  533. public static unsafe int NativeIntAddCheck(int a)
  534. {
  535. return (int)(&a + 1) - (int)&a;
  536. }
  537. public unsafe struct PointerArithmetic : IJob, IDisposable
  538. {
  539. [NativeDisableUnsafePtrRestriction] public int** pointers;
  540. public void Execute()
  541. {
  542. pointers[10] = pointers[10] + +1;
  543. pointers[20] = pointers[20] - +1;
  544. pointers[30] = pointers[30] - -1;
  545. pointers[40] = pointers[40] + -1;
  546. }
  547. public struct Provider : IArgumentProvider
  548. {
  549. public object Value
  550. {
  551. get
  552. {
  553. var value = new PointerArithmetic();
  554. value.pointers = (int**)UnsafeUtility.Malloc(1000*sizeof(int*), 8, Allocator.Persistent);
  555. UnsafeUtility.MemClear(value.pointers, 1000 * sizeof(int*));
  556. return value;
  557. }
  558. }
  559. }
  560. public void Dispose()
  561. {
  562. UnsafeUtility.Free(pointers, Allocator.Persistent);
  563. }
  564. }
  565. // The arithmetic test has been split to make it easier to see the mismatched value (rather than true!=false)
  566. // According to : https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code#pointer-types
  567. // Conversion between pointers and integrals is "Implementation Defined".
  568. [TestCompiler(typeof(PointerArithmetic.Provider))]
  569. public static unsafe Int64 TestArithmeticPointerA(ref PointerArithmetic job)
  570. {
  571. job.Execute();
  572. if (sizeof(int*) == 4)
  573. return (Int64)(UInt32)(job.pointers[10]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
  574. return (Int64)job.pointers[10];
  575. }
  576. [TestCompiler(typeof(PointerArithmetic.Provider))]
  577. public static unsafe Int64 TestArithmeticPointerB(ref PointerArithmetic job)
  578. {
  579. job.Execute();
  580. if (sizeof(int*) == 4)
  581. return (Int64)(UInt32)(job.pointers[20]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
  582. return (Int64)job.pointers[20];
  583. }
  584. [TestCompiler(typeof(PointerArithmetic.Provider))]
  585. public static unsafe Int64 TestArithmeticPointerC(ref PointerArithmetic job)
  586. {
  587. job.Execute();
  588. if (sizeof(int*) == 4)
  589. return (Int64)(UInt32)(job.pointers[30]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
  590. return (Int64)job.pointers[30];
  591. }
  592. [TestCompiler(typeof(PointerArithmetic.Provider))]
  593. public static unsafe Int64 TestArithmeticPointerD(ref PointerArithmetic job)
  594. {
  595. job.Execute();
  596. if (sizeof(int*) == 4)
  597. return (Int64)(UInt32)(job.pointers[40]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
  598. return (Int64)job.pointers[40];
  599. }
  600. [TestCompiler]
  601. public static unsafe int TestSystemBufferMemoryCopy()
  602. {
  603. var a = stackalloc int[2];
  604. a[0] = 42;
  605. System.Buffer.MemoryCopy(a + 0, a + 1, UnsafeUtility.SizeOf<int>(), UnsafeUtility.SizeOf<int>());
  606. return a[1];
  607. }
  608. }
  609. }