/* Build an array of a particular type */ public static unsafe T[] CreateSZArray <T>(int nitems, void *data_addr) { TysosType arrtt = (TysosType)typeof(T[]); TysosType elemtt = (TysosType)typeof(T); int elemsize; if (elemtt.IsValueType) { elemsize = elemtt.GetClassSize() - ClassOperations.GetBoxedTypeDataOffset(); } else { elemsize = OtherOperations.GetPointerSize(); } if (data_addr == null) { data_addr = MemoryOperations.GcMalloc(elemsize * nitems); } byte *ret = (byte *)MemoryOperations.GcMalloc(ArrayOperations.GetArrayClassSize() + 8); // extra space for lobounds and length array void *vtbl = *(void **)((byte *)CastOperations.ReinterpretAsPointer(arrtt) + ClassOperations.GetSystemTypeImplOffset()); *(void **)(ret + ClassOperations.GetVtblFieldOffset()) = vtbl; *(ulong *)(ret + ClassOperations.GetMutexLockOffset()) = 0; *(void **)(ret + ArrayOperations.GetElemTypeOffset()) = *(void **)((byte *)CastOperations.ReinterpretAsPointer(elemtt) + ClassOperations.GetSystemTypeImplOffset()); *(int *)(ret + ArrayOperations.GetElemSizeOffset()) = elemsize; *(void **)(ret + ArrayOperations.GetInnerArrayOffset()) = data_addr; *(void **)(ret + ArrayOperations.GetLoboundsOffset()) = ret + ArrayOperations.GetArrayClassSize(); *(void **)(ret + ArrayOperations.GetSizesOffset()) = ret + ArrayOperations.GetArrayClassSize() + 4; *(int *)(ret + ArrayOperations.GetRankOffset()) = 1; *(int *)(ret + ArrayOperations.GetArrayClassSize()) = 0; // lobounds[0] *(int *)(ret + ArrayOperations.GetArrayClassSize() + 4) = nitems; // sizes[0] return((T[])CastOperations.ReinterpretAsObject(ret)); }
static unsafe void InternalGetReference(void *arr, System.TypedReference *typedref, int ranks, int *rank_indices) { // idx = rightmost-index + 2nd-right * rightmost-size + 3rd-right * 2nd-right-size * right-size + ... // rank checking is done by System.Array members in coreclr int *lovals = *(int **)((byte *)arr + ArrayOperations.GetLoboundsOffset()); int *sizes = *(int **)((byte *)arr + ArrayOperations.GetSizesOffset()); // first get index of first rank if (rank_indices[0] > sizes[0]) { throw new IndexOutOfRangeException(); } int index = rank_indices[0] - lovals[0]; // now repeat mul rank size; add rank index; rank-1 times for (int rank = 1; rank < ranks; rank++) { if (rank_indices[rank] > sizes[rank]) { throw new IndexOutOfRangeException(); } index *= sizes[rank]; index += rank_indices[rank]; } // get pointer to actual data int et_size = *(int *)((byte *)arr + ArrayOperations.GetElemSizeOffset()); void *ptr = *(byte **)((byte *)arr + ArrayOperations.GetInnerArrayOffset()) + index * et_size; // store to the typed reference *(void **)((byte *)typedref + ClassOperations.GetTypedReferenceValueOffset()) = ptr; *(void **)((byte *)typedref + ClassOperations.GetTypedReferenceTypeOffset()) = *(void **)((byte *)arr + ArrayOperations.GetElemTypeOffset()); }
static unsafe void *GetValueImpl(void *arr, int pos) { /* Get the element type of the array */ void *et = *(void **)((byte *)arr + ArrayOperations.GetElemTypeOffset()); /* Get a pointer to the source data */ var elem_size = *(int *)((byte *)arr + ArrayOperations.GetElemSizeOffset()); void *ia = *(void **)((byte *)arr + ArrayOperations.GetInnerArrayOffset()); void *sptr = (void *)((byte *)ia + pos * elem_size); /* Is this a value type? In which case we need to return a boxed value */ void *extends = *(void **)((byte *)et + ClassOperations.GetVtblExtendsVtblPtrOffset()); if (extends == OtherOperations.GetStaticObjectAddress("_Zu1L") || extends == OtherOperations.GetStaticObjectAddress("_ZW6System4Enum")) { /* This is a value type. We need to read the size of the element, * create a new object of the appropriate size and copy the data * into it */ byte *ret = (byte *)MemoryOperations.GcMalloc(elem_size + ClassOperations.GetBoxedTypeDataOffset()); *(void **)(ret + ClassOperations.GetVtblFieldOffset()) = et; *(ulong *)(ret + ClassOperations.GetMutexLockOffset()) = 0; /* Avoid calls to memcpy if possible */ switch (elem_size) { case 1: *(byte *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(byte *)sptr; return(ret); case 2: *(ushort *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(ushort *)sptr; return(ret); case 4: *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(uint *)sptr; return(ret); case 8: if (OtherOperations.GetPointerSize() >= 8) { *(ulong *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(ulong *)sptr; return(ret); } else { *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(uint *)sptr; *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset() + 4) = *(uint *)((byte *)sptr + 4); return(ret); } case 16: if (OtherOperations.GetPointerSize() >= 8) { *(ulong *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(ulong *)sptr; *(ulong *)(ret + ClassOperations.GetBoxedTypeDataOffset() + 8) = *(ulong *)((byte *)sptr + 8); return(ret); } else { *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset()) = *(uint *)sptr; *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset() + 4) = *(uint *)((byte *)sptr + 4); *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset() + 8) = *(uint *)((byte *)sptr + 8); *(uint *)(ret + ClassOperations.GetBoxedTypeDataOffset() + 12) = *(uint *)((byte *)sptr + 12); return(ret); } } /* Do data copy via memcpy */ MemoryOperations.MemCpy(ret + ClassOperations.GetBoxedTypeDataOffset(), sptr, elem_size); return(ret); } else { /* Its a reference type, so just return the pointer */ return(*(void **)sptr); } }
static unsafe void Copy(void *srcArr, int srcIndex, void *dstArr, int dstIndex, int length, bool reliable) { /* Ensure arrays are valid */ if (srcArr == null || dstArr == null) { throw new ArgumentNullException(); } /* Ensure length is valid */ if (length < 0) { throw new ArgumentOutOfRangeException(); } /* Ensure both arrays are of the same rank */ var srcRank = *(int *)((byte *)srcArr + ArrayOperations.GetRankOffset()); var dstRank = *(int *)((byte *)dstArr + ArrayOperations.GetRankOffset()); if (srcRank != dstRank) { throw new RankException(); } /* Get source and dest element types */ var srcET = *(void **)((byte *)srcArr + ArrayOperations.GetElemTypeOffset()); var dstET = *(void **)((byte *)dstArr + ArrayOperations.GetElemTypeOffset()); /* See if we can do a quick copy */ bool can_quick_copy = false; if (srcET == dstET) { can_quick_copy = true; } else if (TysosType.CanCast(srcET, dstET)) { can_quick_copy = true; } else if (reliable) { throw new ArrayTypeMismatchException(); /* ConstrainedCopy requires types to be the same or derived */ } else { can_quick_copy = false; } /* For now we don't handle arrays with lobounds != 0 */ var srcLobounds = *(int **)((byte *)srcArr + ArrayOperations.GetLoboundsOffset()); var dstLobounds = *(int **)((byte *)dstArr + ArrayOperations.GetLoboundsOffset()); for (int i = 0; i < srcRank; i++) { if (srcLobounds[i] != 0) { throw new NotImplementedException("srcLobounds != 0"); } if (dstLobounds[i] != 0) { throw new NotImplementedException("dstLobounds != 0"); } } if (srcIndex < 0 || dstIndex < 0) { throw new ArgumentOutOfRangeException(); } /* Ensure we don't overflow */ var src_len = GetLength(srcArr); var dst_len = GetLength(dstArr); if (srcIndex + length > src_len) { System.Diagnostics.Debugger.Log(0, "libsupcs", "Array.Copy srcIndex/length out of range"); System.Diagnostics.Debugger.Log(length, "libsupcs", "length"); System.Diagnostics.Debugger.Log(srcIndex, "libsupcs", "srcIndex"); System.Diagnostics.Debugger.Log(src_len, "libsupcs", "src_len"); throw new ArgumentOutOfRangeException(); } if (dstIndex + length > dst_len) { System.Diagnostics.Debugger.Log(0, "libsupcs", "Array.Copy dstIndex/length out of range"); System.Diagnostics.Debugger.Log(length, "libsupcs", "length"); System.Diagnostics.Debugger.Log(dstIndex, "libsupcs", "dstIndex"); System.Diagnostics.Debugger.Log(dst_len, "libsupcs", "dst_len"); throw new ArgumentOutOfRangeException(); } if (can_quick_copy) { /* Elem size of both arrays is guaranteed to be the same and we can do a shallow copy */ var e_size = *(int *)((byte *)srcArr + ArrayOperations.GetElemSizeOffset()); var src_ia = *(byte **)((byte *)srcArr + ArrayOperations.GetInnerArrayOffset()); var dst_ia = *(byte **)((byte *)dstArr + ArrayOperations.GetInnerArrayOffset()); MemoryOperations.MemMove(dst_ia + dstIndex * e_size, src_ia + srcIndex * e_size, length * e_size); } else { /* TODO: implement as per System.Array.Copy() semantics */ throw new NotImplementedException("Cannot quick copy " + ((ulong)srcET).ToString("X") + " to " + ((ulong)dstET).ToString("X")); } }
static unsafe bool FastCopy(void *srcArr, int srcIndex, void *dstArr, int dstIndex, int length) { /* This is often called with length == 0 when the * first item is added to a List<T> as the default * array within the list has length 0. */ if (length == 0) { return(true); } // Ensure both arrays are of rank 1 int srcRank = *(int *)((byte *)srcArr + ArrayOperations.GetRankOffset()); int dstRank = *(int *)((byte *)dstArr + ArrayOperations.GetRankOffset()); if (srcRank != 1) { return(false); } if (dstRank != 1) { return(false); } // Ensure srcIndex is valid int srcLobound = **(int **)((byte *)srcArr + ArrayOperations.GetLoboundsOffset()); int srcSize = **(int **)((byte *)srcArr + ArrayOperations.GetSizesOffset()); srcIndex -= srcLobound; if (srcIndex + length > srcSize) { return(false); } // Ensure destIndex is valid int dstLobound = **(int **)((byte *)dstArr + ArrayOperations.GetLoboundsOffset()); int dstSize = **(int **)((byte *)dstArr + ArrayOperations.GetSizesOffset()); dstIndex -= dstLobound; if (dstIndex + length > dstSize) { return(false); } // Ensure both have same element type void *srcET = *(void **)((byte *)srcArr + ArrayOperations.GetElemTypeOffset()); void *dstET = *(void **)((byte *)dstArr + ArrayOperations.GetElemTypeOffset()); if (srcET != dstET) { return(false); } // Get element size int elemSize = *(int *)((byte *)srcArr + ArrayOperations.GetElemSizeOffset()); srcIndex *= elemSize; dstIndex *= elemSize; byte *srcAddr = *(byte **)((byte *)srcArr + ArrayOperations.GetInnerArrayOffset()) + srcIndex; byte *dstAddr = *(byte **)((byte *)dstArr + ArrayOperations.GetInnerArrayOffset()) + dstIndex; length *= elemSize; MemoryOperations.MemMove(dstAddr, srcAddr, length); return(true); }