No Description
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.

Array.cpp 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include "il2cpp-config.h"
  2. #include "gc/gc_wrapper.h"
  3. #include "gc/GarbageCollector.h"
  4. #include "vm/Array.h"
  5. #include "vm/Class.h"
  6. #include "vm/Exception.h"
  7. #include "vm/Object.h"
  8. #include "vm/Profiler.h"
  9. #include "il2cpp-class-internals.h"
  10. #include "il2cpp-object-internals.h"
  11. #include <memory>
  12. namespace il2cpp
  13. {
  14. namespace vm
  15. {
  16. Il2CppArray* Array::Clone(Il2CppArray* arr)
  17. {
  18. Il2CppClass *typeInfo = arr->klass;
  19. const uint32_t elem_size = il2cpp::vm::Array::GetElementSize(typeInfo);
  20. if (arr->bounds == NULL)
  21. {
  22. il2cpp_array_size_t len = il2cpp::vm::Array::GetLength(arr);
  23. Il2CppArray *clone = (Il2CppArray*)il2cpp::vm::Array::NewFull(typeInfo, &len, NULL);
  24. memcpy(il2cpp::vm::Array::GetFirstElementAddress(clone), il2cpp::vm::Array::GetFirstElementAddress(arr), elem_size * len);
  25. gc::GarbageCollector::SetWriteBarrier((void**)il2cpp::vm::Array::GetFirstElementAddress(clone), elem_size * len);
  26. return clone;
  27. }
  28. il2cpp_array_size_t size = elem_size;
  29. std::vector<il2cpp_array_size_t> lengths(typeInfo->rank);
  30. std::vector<il2cpp_array_size_t> lowerBounds(typeInfo->rank);
  31. for (int i = 0; i < typeInfo->rank; ++i)
  32. {
  33. lengths[i] = arr->bounds[i].length;
  34. size *= arr->bounds[i].length;
  35. lowerBounds[i] = arr->bounds[i].lower_bound;
  36. }
  37. Il2CppArray* clone = il2cpp::vm::Array::NewFull(typeInfo, &lengths[0], &lowerBounds[0]);
  38. memcpy(il2cpp::vm::Array::GetFirstElementAddress(clone), il2cpp::vm::Array::GetFirstElementAddress(arr), size);
  39. gc::GarbageCollector::SetWriteBarrier((void**)il2cpp::vm::Array::GetFirstElementAddress(clone), size);
  40. return clone;
  41. }
  42. int32_t Array::GetElementSize(const Il2CppClass *klass)
  43. {
  44. IL2CPP_ASSERT(klass->rank);
  45. return klass->element_size;
  46. }
  47. uint32_t Array::GetLength(Il2CppArray* array)
  48. {
  49. return ARRAY_LENGTH_AS_INT32(array->max_length);
  50. }
  51. uint32_t Array::GetByteLength(Il2CppArray* array)
  52. {
  53. Il2CppClass *klass;
  54. il2cpp_array_size_t length;
  55. int i;
  56. klass = array->klass;
  57. if (array->bounds == NULL)
  58. length = array->max_length;
  59. else
  60. {
  61. length = 1;
  62. for (i = 0; i < klass->rank; ++i)
  63. length *= array->bounds[i].length;
  64. }
  65. return ARRAY_LENGTH_AS_INT32(length * GetElementSize(klass));
  66. }
  67. Il2CppArray* Array::New(Il2CppClass *elementTypeInfo, il2cpp_array_size_t length)
  68. {
  69. return NewSpecific(Class::GetArrayClass(elementTypeInfo, 1), length);
  70. }
  71. static void RaiseOverflowException()
  72. {
  73. vm::Exception::Raise(vm::Exception::GetOverflowException("Arithmetic operation resulted in an overflow."));
  74. }
  75. Il2CppArray* Array::NewSpecific(Il2CppClass *klass, il2cpp_array_size_t n)
  76. {
  77. Il2CppObject *o;
  78. Il2CppArray *ao;
  79. uint32_t elem_size;
  80. il2cpp_array_size_t byte_len;
  81. Class::Init(klass);
  82. IL2CPP_ASSERT(klass->rank);
  83. IL2CPP_ASSERT(klass->initialized);
  84. IL2CPP_ASSERT(klass->element_class->initialized);
  85. IL2CPP_ASSERT(klass->byval_arg.type == IL2CPP_TYPE_SZARRAY);
  86. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewSpecific, "Not checking for overflow");
  87. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewSpecific, "Handle allocations with a GC descriptor");
  88. if (n > IL2CPP_ARRAY_MAX_INDEX)
  89. {
  90. RaiseOverflowException();
  91. return NULL;
  92. }
  93. elem_size = il2cpp_array_element_size(klass);
  94. //if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
  95. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  96. // return NULL;
  97. //}
  98. byte_len = n * elem_size;
  99. //if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
  100. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  101. // return NULL;
  102. //}
  103. byte_len += kIl2CppSizeOfArray;
  104. if (!klass->has_references)
  105. {
  106. o = Object::AllocatePtrFree(byte_len, klass);
  107. #if NEED_TO_ZERO_PTRFREE
  108. ((Il2CppArray*)o)->bounds = NULL;
  109. memset((char*)o + sizeof(Il2CppObject), 0, byte_len - sizeof(Il2CppObject));
  110. #endif
  111. }
  112. else if (klass->element_class->byval_arg.valuetype &&
  113. ((GC_descr)klass->element_class->gc_desc & GC_DS_TAGS) == GC_DS_BITMAP)
  114. {
  115. o = (Il2CppObject*)GC_gcj_vector_malloc(byte_len, klass);
  116. }
  117. #if IL2CPP_HAS_GC_DESCRIPTORS
  118. else if (klass->gc_desc != GC_NO_DESCRIPTOR)
  119. {
  120. o = Object::AllocateSpec(byte_len, klass);
  121. }
  122. #endif
  123. else
  124. {
  125. o = Object::Allocate(byte_len, klass);
  126. }
  127. ao = (Il2CppArray*)o;
  128. ao->max_length = n;
  129. #if IL2CPP_ENABLE_PROFILER
  130. if (Profiler::ProfileAllocations())
  131. Profiler::Allocation(o, klass);
  132. #endif
  133. return ao;
  134. }
  135. Il2CppArray* Array::NewFull(Il2CppClass *array_class, il2cpp_array_size_t *lengths, il2cpp_array_size_t *lower_bounds)
  136. {
  137. il2cpp_array_size_t byte_len, len, bounds_size;
  138. Il2CppObject *o;
  139. Il2CppArray *array;
  140. int i;
  141. Class::Init(array_class);
  142. IL2CPP_ASSERT(array_class->rank);
  143. IL2CPP_ASSERT(array_class->initialized);
  144. IL2CPP_ASSERT(array_class->element_class->initialized);
  145. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewFull, "IGNORING non-zero based arrays!");
  146. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewFull, "Handle allocations with a GC descriptor");
  147. byte_len = il2cpp_array_element_size(array_class);
  148. len = 1;
  149. /* A single dimensional array with a 0 lower bound is the same as an szarray */
  150. if (array_class->rank == 1 && ((array_class->byval_arg.type == IL2CPP_TYPE_SZARRAY) || (lower_bounds && lower_bounds[0] == 0)))
  151. {
  152. /* A single dimensional array with a 0 lower bound should be an szarray */
  153. /* but the caller asked for an IL2CPP_TYPE_ARRAY, which insn't correct */
  154. IL2CPP_ASSERT(array_class->byval_arg.type == IL2CPP_TYPE_SZARRAY);
  155. len = lengths[0];
  156. if (len > IL2CPP_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
  157. RaiseOverflowException();
  158. bounds_size = 0;
  159. }
  160. else
  161. {
  162. IL2CPP_ASSERT(array_class->byval_arg.type == IL2CPP_TYPE_ARRAY);
  163. bounds_size = sizeof(Il2CppArrayBounds) * array_class->rank;
  164. for (i = 0; i < array_class->rank; ++i)
  165. {
  166. if (lengths[i] > IL2CPP_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
  167. RaiseOverflowException();
  168. //if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
  169. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  170. len *= lengths[i];
  171. }
  172. }
  173. //if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
  174. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  175. byte_len *= len;
  176. //if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
  177. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  178. byte_len += kIl2CppSizeOfArray;
  179. if (bounds_size)
  180. {
  181. /* align */
  182. //if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
  183. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  184. byte_len = (byte_len + (IL2CPP_SIZEOF_VOID_P - 1)) & ~(IL2CPP_SIZEOF_VOID_P - 1);
  185. //if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
  186. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  187. byte_len += bounds_size;
  188. }
  189. /*
  190. * Following three lines almost taken from mono_object_new ():
  191. * they need to be kept in sync.
  192. */
  193. if (!array_class->has_references)
  194. {
  195. o = Object::AllocatePtrFree(byte_len, array_class);
  196. #if NEED_TO_ZERO_PTRFREE
  197. memset((char*)o + sizeof(Il2CppObject), 0, byte_len - sizeof(Il2CppObject));
  198. #endif
  199. }
  200. #if IL2CPP_HAS_GC_DESCRIPTORS
  201. else if (array_class->gc_desc != GC_NO_DESCRIPTOR)
  202. {
  203. o = Object::AllocateSpec(byte_len, array_class);
  204. }
  205. #endif
  206. else
  207. {
  208. o = Object::Allocate(byte_len, array_class);
  209. }
  210. array = (Il2CppArray*)o;
  211. array->max_length = len;
  212. if (bounds_size)
  213. {
  214. Il2CppArrayBounds *bounds = (Il2CppArrayBounds*)((char*)array + byte_len - bounds_size);
  215. array->bounds = bounds;
  216. for (i = 0; i < array_class->rank; ++i)
  217. {
  218. bounds[i].length = lengths[i];
  219. if (lower_bounds)
  220. bounds[i].lower_bound = ARRAY_LENGTH_AS_INT32(lower_bounds[i]);
  221. }
  222. }
  223. #if IL2CPP_ENABLE_PROFILER
  224. if (Profiler::ProfileAllocations())
  225. Profiler::Allocation(o, array_class);
  226. #endif
  227. return array;
  228. }
  229. char* Array::GetFirstElementAddress(Il2CppArray *array)
  230. {
  231. return reinterpret_cast<char*>(array) + kIl2CppSizeOfArray;
  232. }
  233. il2cpp_array_size_t Array::IndexFromIndices(Il2CppArray* thisPtr, int32_t const * indices)
  234. {
  235. int32_t i;
  236. il2cpp_array_size_t pos;
  237. Il2CppClass* ac;
  238. ac = thisPtr->klass;
  239. pos = indices[0] - thisPtr->bounds[0].lower_bound;
  240. for (i = 1; i < ac->rank; i++)
  241. pos = pos * thisPtr->bounds[i].length + indices[i] -
  242. thisPtr->bounds[i].lower_bound;
  243. return pos;
  244. }
  245. } /* namespace vm */
  246. } /* namespace il2cpp */
  247. LIBIL2CPP_CODEGEN_API int32_t
  248. il2cpp_array_element_size(Il2CppClass *ac)
  249. {
  250. return il2cpp::vm::Array::GetElementSize(ac);
  251. }