Object.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #include "il2cpp-config.h"
  2. #include <memory>
  3. #include "il2cpp-class-internals.h"
  4. #include "il2cpp-object-internals.h"
  5. #include "il2cpp-tabledefs.h"
  6. #include "il2cpp-runtime-stats.h"
  7. #include "gc/gc_wrapper.h"
  8. #include "gc/GarbageCollector.h"
  9. #include "metadata/GenericMethod.h"
  10. #include "metadata/Il2CppTypeCompare.h"
  11. #include "utils/StringUtils.h"
  12. #include "vm-utils/VmThreadUtils.h"
  13. #include "vm/Array.h"
  14. #include "vm/Class.h"
  15. #include "vm/ClassInlines.h"
  16. #include "vm/Exception.h"
  17. #include "vm/Field.h"
  18. #include "vm/MetadataCache.h"
  19. #include "vm/Method.h"
  20. #include "vm/Object.h"
  21. #include "vm/Profiler.h"
  22. #include "vm/RCW.h"
  23. #include "vm/Reflection.h"
  24. #include "vm/Runtime.h"
  25. #include "vm/String.h"
  26. #include "vm/Thread.h"
  27. #include "vm/Type.h"
  28. #if IL2CPP_GC_BOEHM
  29. #define ALLOC_PTRFREE(obj, vt, size) do { (obj) = (Il2CppObject*)GC_MALLOC_ATOMIC ((size)); (obj)->klass = (vt); (obj)->monitor = NULL;} while (0)
  30. #define ALLOC_OBJECT(obj, vt, size) do { (obj) = (Il2CppObject*)GC_MALLOC ((size)); (obj)->klass = (vt);} while (0)
  31. #ifdef GC_GCJ_SUPPORT
  32. #define ALLOC_TYPED(dest, size, type) do { (dest) = (Il2CppObject*)GC_gcj_malloc ((size),(type)); } while (0)
  33. #else
  34. #define GC_NO_DESCRIPTOR (NULL)
  35. #define ALLOC_TYPED(dest, size, type) do { (dest) = GC_MALLOC ((size)); *(void**)dest = (type);} while (0)
  36. #endif
  37. #else
  38. #ifdef HAVE_SGEN_GC
  39. #define GC_NO_DESCRIPTOR (NULL)
  40. #define ALLOC_PTRFREE(obj, vt, size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
  41. #define ALLOC_OBJECT(obj, vt, size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
  42. #define ALLOC_TYPED(dest, size, type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
  43. #else
  44. #define ALLOC_PTRFREE(obj, vt, size) do { (obj) = (Il2CppObject*)malloc ((size)); (obj)->klass = (vt); (obj)->monitor = NULL;} while (0)
  45. #define ALLOC_OBJECT(obj, vt, size) do { (obj) = (Il2CppObject*)calloc (1, (size)); (obj)->klass = (vt);} while (0)
  46. #define ALLOC_TYPED(dest, size, type) do { (dest) = (Il2CppObject*)(calloc (1, (size))); *(void**)dest = (type);} while (0)
  47. #endif
  48. #endif
  49. namespace il2cpp
  50. {
  51. namespace vm
  52. {
  53. Il2CppObject * Object::Allocate(size_t size, Il2CppClass *typeInfo)
  54. {
  55. IL2CPP_ASSERT(typeInfo->initialized);
  56. Il2CppObject *o;
  57. ALLOC_OBJECT(o, typeInfo, size);
  58. ++il2cpp_runtime_stats.new_object_count;
  59. return o;
  60. }
  61. Il2CppObject * Object::AllocatePtrFree(size_t size, Il2CppClass *typeInfo)
  62. {
  63. IL2CPP_ASSERT(typeInfo->initialized);
  64. Il2CppObject *o;
  65. ALLOC_PTRFREE(o, typeInfo, size);
  66. ++il2cpp_runtime_stats.new_object_count;
  67. return o;
  68. }
  69. Il2CppObject * Object::AllocateSpec(size_t size, Il2CppClass *typeInfo)
  70. {
  71. IL2CPP_ASSERT(typeInfo->initialized);
  72. Il2CppObject *o;
  73. ALLOC_TYPED(o, size, typeInfo);
  74. ++il2cpp_runtime_stats.new_object_count;
  75. return o;
  76. }
  77. Il2CppObject* Object::Box(Il2CppClass *typeInfo, void* val)
  78. {
  79. if (!typeInfo->byval_arg.valuetype)
  80. return *(Il2CppObject**)val;
  81. bool isNullable = Class::IsNullable(typeInfo);
  82. if (isNullable)
  83. {
  84. /* From ECMA-335, I.8.2.4 Boxing and unboxing of values:
  85. All value types have an operation called box. Boxing a value of any value type produces its boxed value;
  86. i.e., a value of the corresponding boxed type containing a bitwise copy of the original value. If the
  87. value type is a nullable type defined as an instantiation of the value type System.Nullable<T> the result
  88. is a null reference or bitwise copy of its Value property of type T, depending on its HasValue property
  89. (false and true, respectively).
  90. */
  91. if (!NullableHasValue(typeInfo, val))
  92. return NULL;
  93. }
  94. Il2CppObject* obj = Object::New(typeInfo);
  95. size_t size = Class::GetInstanceSize(typeInfo);
  96. // At this point we know we have a value type and we need to adjust the
  97. // copy size by the size of Il2CppObject
  98. size = size - sizeof(Il2CppObject);
  99. uint8_t* valueStart = static_cast<uint8_t*>(val);
  100. if (isNullable)
  101. {
  102. IL2CPP_ASSERT(metadata::Il2CppTypeEqualityComparer::AreEqual(typeInfo->fields[1].type, &Class::GetNullableArgument(typeInfo)->byval_arg));
  103. // Shift the valueStart right past the bool for nullable
  104. int32_t nullableShift = typeInfo->fields[1].offset - sizeof(Il2CppObject);
  105. valueStart += nullableShift;
  106. // the size needs to be further adjusted to be smaller
  107. size -= nullableShift;
  108. }
  109. memcpy(((char*)obj) + sizeof(Il2CppObject), valueStart, size);
  110. gc::GarbageCollector::SetWriteBarrier((void**)(((char*)obj) + sizeof(Il2CppObject)), size);
  111. return obj;
  112. }
  113. Il2CppObject* Object::Clone(Il2CppObject *obj)
  114. {
  115. Il2CppObject *o;
  116. int size;
  117. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Object::Clone, "Finish implementation");
  118. if (obj->klass->rank)
  119. {
  120. return Array::Clone((Il2CppArray*)obj);
  121. }
  122. size = obj->klass->instance_size;
  123. o = Allocate(size, obj->klass);
  124. /* do not copy the sync state */
  125. memcpy((char*)o + sizeof(Il2CppObject), (char*)obj + sizeof(Il2CppObject), size - sizeof(Il2CppObject));
  126. gc::GarbageCollector::SetWriteBarrier((void**)(((char*)o) + sizeof(Il2CppObject)), size);
  127. //#ifdef HAVE_SGEN_GC
  128. // if (obj->vtable->klass->has_references)
  129. // mono_gc_wbarrier_object (o);
  130. //#endif
  131. if (obj->klass->has_finalize)
  132. il2cpp::gc::GarbageCollector::RegisterFinalizerForNewObject(o);
  133. #if IL2CPP_ENABLE_PROFILER
  134. if (Profiler::ProfileAllocations())
  135. Profiler::Allocation(o, obj->klass);
  136. #endif
  137. return o;
  138. }
  139. Il2CppClass* Object::GetClass(Il2CppObject* obj)
  140. {
  141. return obj->klass;
  142. }
  143. #if IL2CPP_SIZEOF_VOID_P == 8
  144. const int kObjectAlignmentShift = 3;
  145. #elif IL2CPP_SIZEOF_VOID_P == 4
  146. const int kObjectAlignmentShift = 2;
  147. #else
  148. #error Invalid architecture size
  149. #endif
  150. int32_t Object::GetHash(Il2CppObject* obj)
  151. {
  152. // shift away unused bits due to alignment, then use Knuth's multiplicative hash
  153. return (((uint32_t)(intptr_t)(obj)) >> kObjectAlignmentShift) * 2654435761u;
  154. }
  155. uint32_t Object::GetSize(Il2CppObject* obj)
  156. {
  157. Il2CppClass* klass = GetClass(obj);
  158. if (klass == il2cpp_defaults.string_class)
  159. {
  160. return sizeof(Il2CppString) + 2 * utils::StringUtils::GetLength((Il2CppString*)obj) + 2;
  161. }
  162. else if (obj->klass->rank)
  163. {
  164. Il2CppArray *array = (Il2CppArray*)obj;
  165. size_t size = kIl2CppSizeOfArray + Array::GetElementSize(klass) * Array::GetLength(array);
  166. if (array->bounds)
  167. {
  168. size += 3;
  169. size &= ~3;
  170. size += sizeof(Il2CppArrayBounds) * obj->klass->rank;
  171. }
  172. return (uint32_t)size;
  173. }
  174. else
  175. {
  176. return Class::GetInstanceSize(klass);
  177. }
  178. }
  179. const MethodInfo* Object::GetVirtualMethod(Il2CppObject *obj, const MethodInfo *virtualMethod)
  180. {
  181. if ((virtualMethod->flags & METHOD_ATTRIBUTE_FINAL) || !(virtualMethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
  182. return virtualMethod;
  183. Il2CppClass* methodDeclaringType = virtualMethod->klass;
  184. const MethodInfo* vtableSlotMethod;
  185. if (Class::IsInterface(methodDeclaringType))
  186. {
  187. vtableSlotMethod = ClassInlines::GetInterfaceInvokeDataFromVTable(obj, methodDeclaringType, virtualMethod->slot).method;
  188. }
  189. else
  190. {
  191. IL2CPP_ASSERT(virtualMethod->slot < obj->klass->vtable_count);
  192. vtableSlotMethod = obj->klass->vtable[virtualMethod->slot].method;
  193. if(vtableSlotMethod == NULL)
  194. {
  195. vtableSlotMethod = Class::GetOrSetupOneVTableSlot(obj->klass, NULL, virtualMethod->slot)->method;
  196. }
  197. }
  198. if (Method::IsGenericInstanceMethod(virtualMethod))
  199. return il2cpp::metadata::GenericMethod::GetGenericVirtualMethod(vtableSlotMethod, virtualMethod);
  200. return vtableSlotMethod;
  201. }
  202. Il2CppObject* Object::IsInst(Il2CppObject *obj, Il2CppClass *klass)
  203. {
  204. if (!obj)
  205. return NULL;
  206. Il2CppClass* objClass = Object::GetClass(obj);
  207. if (Class::IsAssignableFrom(klass, objClass))
  208. return obj;
  209. #if !IL2CPP_TRIM_COM
  210. if (!objClass->is_import_or_windows_runtime)
  211. return NULL;
  212. // check if klass has an interface id
  213. if (Class::IsInterface(klass) && klass->interopData != NULL)
  214. {
  215. const Il2CppGuid* iid = klass->interopData->guid;
  216. if (iid != NULL)
  217. {
  218. Il2CppIUnknown* unknown = RCW::QueryInterfaceNoAddRef<false>(static_cast<Il2CppComObject*>(obj), *iid);
  219. if (unknown)
  220. return static_cast<Il2CppComObject*>(obj);
  221. }
  222. }
  223. #endif
  224. return (klass == il2cpp_defaults.object_class) ? obj : NULL;
  225. }
  226. Il2CppObject* Object::New(Il2CppClass *klass)
  227. {
  228. // same as NewAllocSpecific as we only support a single domain
  229. return NewAllocSpecific(klass);
  230. }
  231. Il2CppObject* Object::NewPinned(Il2CppClass *klass)
  232. {
  233. #if (IL2CPP_GC_BOEHM || IL2CPP_GC_NULL)
  234. return New(klass);
  235. #else
  236. IL2CPP_NOT_IMPLEMENTED(Object::NewPinned);
  237. #endif
  238. }
  239. Il2CppObject * Object::NewAllocSpecific(Il2CppClass *klass)
  240. {
  241. Il2CppObject *o = NULL;
  242. IL2CPP_NOT_IMPLEMENTED_NO_ASSERT(Object::NewAllocSpecific, "We really shouldn't need this initialization");
  243. Class::Init(klass);
  244. if (Class::IsNullable(klass))
  245. klass = il2cpp::vm::Class::GetNullableArgument(klass);
  246. if (!klass->has_references)
  247. {
  248. o = NewPtrFree(klass);
  249. }
  250. #if IL2CPP_HAS_GC_DESCRIPTORS
  251. else if (klass->gc_desc != GC_NO_DESCRIPTOR)
  252. {
  253. o = AllocateSpec(klass->instance_size, klass);
  254. }
  255. #endif
  256. else
  257. {
  258. o = Allocate(klass->instance_size, klass);
  259. }
  260. if (klass->has_finalize)
  261. il2cpp::gc::GarbageCollector::RegisterFinalizerForNewObject(o);
  262. #if IL2CPP_ENABLE_PROFILER
  263. if (Profiler::ProfileAllocations())
  264. Profiler::Allocation(o, klass);
  265. #endif
  266. Runtime::ClassInit(klass);
  267. return o;
  268. }
  269. Il2CppObject* Object::NewPtrFree(Il2CppClass *klass)
  270. {
  271. Il2CppObject *obj = {0};
  272. IL2CPP_ASSERT(klass->initialized);
  273. IL2CPP_ASSERT(!klass->has_references);
  274. ALLOC_PTRFREE(obj, klass, klass->instance_size);
  275. #if NEED_TO_ZERO_PTRFREE
  276. /* an inline memset is much faster for the common vcase of small objects
  277. * note we assume the allocated size is a multiple of sizeof (void*).
  278. */
  279. if (klass->instance_size < 128)
  280. {
  281. void* *p, *end;
  282. end = (void**)((char*)obj + klass->instance_size);
  283. p = (void**)((char*)obj + sizeof(Il2CppObject));
  284. while (p < end)
  285. {
  286. *p = NULL;
  287. ++p;
  288. }
  289. }
  290. else
  291. {
  292. memset((char*)obj + sizeof(Il2CppObject), 0, klass->instance_size - sizeof(Il2CppObject));
  293. }
  294. #endif
  295. ++il2cpp_runtime_stats.new_object_count;
  296. return obj;
  297. }
  298. void* Object::Unbox(Il2CppObject* obj)
  299. {
  300. void* val = (void*)(((char*)obj) + sizeof(Il2CppObject));
  301. return val;
  302. }
  303. void Object::UnboxNullable(Il2CppObject* obj, Il2CppClass* nullableClass, void* storage)
  304. {
  305. // We assume storage is on the stack, if not we'll need a write barrier
  306. // ==={{ wolong. may storage in heap
  307. // IL2CPP_ASSERT_STACK_PTR(storage);
  308. // ===}} wolong
  309. // After the assert above, we can safely call this method, because the GC will find storage as a root,
  310. // since it is on the stack.
  311. UnboxNullableGCUnsafe(obj, nullableClass, storage);
  312. }
  313. void Object::UnboxNullableWithWriteBarrier(Il2CppObject* obj, Il2CppClass* nullableClass, void* storage)
  314. {
  315. uint32_t valueSize = UnboxNullableGCUnsafe(obj, nullableClass, storage);
  316. il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)storage, valueSize);
  317. }
  318. // Hey! You probably don't want to call this method. Call Object::UnboxNullable or
  319. // Object::UnboxNullableWithWriteBarrier instead.
  320. //
  321. //
  322. // Ok - still here? If you call this method and storage is not on the stack, you need to set a
  323. // GC write barrier for the pointer at storage with a length that is the number of bytes, which
  324. // this method returns. That's what UnboxNullableWithWriteBarrier. Use it!
  325. uint32_t Object::UnboxNullableGCUnsafe(Il2CppObject* obj, Il2CppClass* nullableClass, void* storage)
  326. {
  327. IL2CPP_ASSERT(Class::IsNullable(nullableClass));
  328. IL2CPP_ASSERT(nullableClass->field_count == 2);
  329. IL2CPP_ASSERT(metadata::Il2CppTypeEqualityComparer::AreEqual(nullableClass->fields[0].type, &il2cpp_defaults.boolean_class->byval_arg));
  330. IL2CPP_ASSERT(obj == NULL || metadata::Il2CppTypeEqualityComparer::AreEqual(nullableClass->fields[1].type, &obj->klass->byval_arg));
  331. void* valueField = Field::GetInstanceFieldDataPointer(storage, &nullableClass->fields[1]);
  332. uint32_t valueSize = Class::GetNullableArgument(nullableClass)->instance_size - sizeof(Il2CppObject);
  333. if (obj == NULL)
  334. {
  335. memset(valueField, 0, valueSize);
  336. *(static_cast<uint8_t*>(storage)) = false;
  337. }
  338. else
  339. {
  340. memcpy(valueField, Unbox(obj), valueSize);
  341. *(static_cast<uint8_t*>(storage)) = true;
  342. }
  343. return valueSize;
  344. }
  345. void Object::NullableInit(uint8_t* buf, Il2CppObject* value, Il2CppClass* klass)
  346. {
  347. Il2CppClass *parameterClass = klass->castClass;
  348. IL2CPP_ASSERT(Class::FromIl2CppType(klass->fields[0].type) == il2cpp_defaults.boolean_class);
  349. IL2CPP_ASSERT(Class::FromIl2CppType(klass->fields[1].type) == parameterClass);
  350. *(uint8_t*)(buf + klass->fields[0].offset - sizeof(Il2CppObject)) = value ? 1 : 0;
  351. if (value)
  352. memcpy(buf + klass->fields[1].offset - sizeof(Il2CppObject), Object::Unbox(value), Class::GetValueSize(parameterClass, NULL));
  353. else
  354. memset(buf + klass->fields[1].offset - sizeof(Il2CppObject), 0, Class::GetValueSize(parameterClass, NULL));
  355. }
  356. } /* namespace vm */
  357. } /* namespace il2cpp */