Array.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. #if !RUNTIME_TINY
  113. else if (klass->element_class->byval_arg.valuetype &&
  114. ((GC_descr)klass->element_class->gc_desc & GC_DS_TAGS) == GC_DS_BITMAP)
  115. {
  116. o = (Il2CppObject*)GC_gcj_vector_malloc(byte_len, klass);
  117. }
  118. #endif
  119. #if IL2CPP_HAS_GC_DESCRIPTORS
  120. else if (klass->gc_desc != GC_NO_DESCRIPTOR)
  121. {
  122. o = Object::AllocateSpec(byte_len, klass);
  123. }
  124. #endif
  125. else
  126. {
  127. o = Object::Allocate(byte_len, klass);
  128. }
  129. ao = (Il2CppArray*)o;
  130. ao->max_length = n;
  131. #if IL2CPP_ENABLE_PROFILER
  132. if (Profiler::ProfileAllocations())
  133. Profiler::Allocation(o, klass);
  134. #endif
  135. return ao;
  136. }
  137. Il2CppArray* Array::NewFull(Il2CppClass *array_class, il2cpp_array_size_t *lengths, il2cpp_array_size_t *lower_bounds)
  138. {
  139. il2cpp_array_size_t byte_len, len, bounds_size;
  140. Il2CppObject *o;
  141. Il2CppArray *array;
  142. int i;
  143. Class::Init(array_class);
  144. IL2CPP_ASSERT(array_class->rank);
  145. IL2CPP_ASSERT(array_class->initialized);
  146. IL2CPP_ASSERT(array_class->element_class->initialized);
  147. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewFull, "IGNORING non-zero based arrays!");
  148. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Array::NewFull, "Handle allocations with a GC descriptor");
  149. byte_len = il2cpp_array_element_size(array_class);
  150. len = 1;
  151. /* A single dimensional array with a 0 lower bound is the same as an szarray */
  152. if (array_class->rank == 1 && ((array_class->byval_arg.type == IL2CPP_TYPE_SZARRAY) || (lower_bounds && lower_bounds[0] == 0)))
  153. {
  154. /* A single dimensional array with a 0 lower bound should be an szarray */
  155. /* but the caller asked for an IL2CPP_TYPE_ARRAY, which insn't correct */
  156. IL2CPP_ASSERT(array_class->byval_arg.type == IL2CPP_TYPE_SZARRAY);
  157. len = lengths[0];
  158. if (len > IL2CPP_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
  159. RaiseOverflowException();
  160. bounds_size = 0;
  161. }
  162. else
  163. {
  164. IL2CPP_ASSERT(array_class->byval_arg.type == IL2CPP_TYPE_ARRAY);
  165. bounds_size = sizeof(Il2CppArrayBounds) * array_class->rank;
  166. for (i = 0; i < array_class->rank; ++i)
  167. {
  168. if (lengths[i] > IL2CPP_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
  169. RaiseOverflowException();
  170. //if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
  171. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  172. len *= lengths[i];
  173. }
  174. }
  175. //if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
  176. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  177. byte_len *= len;
  178. //if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
  179. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  180. byte_len += kIl2CppSizeOfArray;
  181. if (bounds_size)
  182. {
  183. /* align */
  184. //if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
  185. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  186. byte_len = (byte_len + (IL2CPP_SIZEOF_VOID_P - 1)) & ~(IL2CPP_SIZEOF_VOID_P - 1);
  187. //if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
  188. // mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
  189. byte_len += bounds_size;
  190. }
  191. /*
  192. * Following three lines almost taken from mono_object_new ():
  193. * they need to be kept in sync.
  194. */
  195. if (!array_class->has_references)
  196. {
  197. o = Object::AllocatePtrFree(byte_len, array_class);
  198. #if NEED_TO_ZERO_PTRFREE
  199. memset((char*)o + sizeof(Il2CppObject), 0, byte_len - sizeof(Il2CppObject));
  200. #endif
  201. }
  202. #if IL2CPP_HAS_GC_DESCRIPTORS
  203. else if (array_class->gc_desc != GC_NO_DESCRIPTOR)
  204. {
  205. o = Object::AllocateSpec(byte_len, array_class);
  206. }
  207. #endif
  208. else
  209. {
  210. o = Object::Allocate(byte_len, array_class);
  211. }
  212. array = (Il2CppArray*)o;
  213. array->max_length = len;
  214. if (bounds_size)
  215. {
  216. Il2CppArrayBounds *bounds = (Il2CppArrayBounds*)((char*)array + byte_len - bounds_size);
  217. array->bounds = bounds;
  218. for (i = 0; i < array_class->rank; ++i)
  219. {
  220. bounds[i].length = lengths[i];
  221. if (lower_bounds)
  222. bounds[i].lower_bound = ARRAY_LENGTH_AS_INT32(lower_bounds[i]);
  223. }
  224. }
  225. #if IL2CPP_ENABLE_PROFILER
  226. if (Profiler::ProfileAllocations())
  227. Profiler::Allocation(o, array_class);
  228. #endif
  229. return array;
  230. }
  231. char* Array::GetFirstElementAddress(Il2CppArray *array)
  232. {
  233. return reinterpret_cast<char*>(array) + kIl2CppSizeOfArray;
  234. }
  235. } /* namespace vm */
  236. } /* namespace il2cpp */
  237. LIBIL2CPP_CODEGEN_API int32_t
  238. il2cpp_array_element_size(Il2CppClass *ac)
  239. {
  240. return il2cpp::vm::Array::GetElementSize(ac);
  241. }