AppendOnlyGCHashMap.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #pragma once
  2. #include "utils/Il2CppHashMap.h"
  3. #include "utils/NonCopyable.h"
  4. #include "GarbageCollector.h"
  5. namespace il2cpp
  6. {
  7. namespace gc
  8. {
  9. template<class Key, class T,
  10. class HashFcn,
  11. class EqualKey = std::equal_to<Key> >
  12. class AppendOnlyGCHashMap : public il2cpp::utils::NonCopyable
  13. {
  14. typedef Il2CppHashMap<Key, size_t, HashFcn, EqualKey> hash_map_type;
  15. typedef typename Il2CppHashMap<Key, size_t, HashFcn, EqualKey>::const_iterator ConstIterator;
  16. public:
  17. typedef typename hash_map_type::key_type key_type;
  18. typedef T data_type;
  19. typedef typename hash_map_type::size_type size_type;
  20. typedef typename hash_map_type::hasher hasher;
  21. typedef typename hash_map_type::key_equal key_equal;
  22. AppendOnlyGCHashMap() :
  23. m_Data(NULL),
  24. m_Size(0)
  25. {
  26. }
  27. ~AppendOnlyGCHashMap()
  28. {
  29. if (m_Data)
  30. il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
  31. }
  32. bool Contains(const Key& k)
  33. {
  34. return m_Map.find(k) != m_Map.end();
  35. }
  36. // Returns true if value was added. False if it already existed
  37. bool Add(const Key& k, T value)
  38. {
  39. if (m_Map.find(k) != m_Map.end())
  40. return false;
  41. if (m_Size == 0)
  42. {
  43. m_Size = 8;
  44. m_Data = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(m_Size * sizeof(T), NULL);
  45. IL2CPP_ASSERT(m_Data);
  46. }
  47. else if (m_Map.size() == m_Size)
  48. {
  49. size_t newSize = 2 * m_Size;
  50. T* newData = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(newSize * sizeof(T), NULL);
  51. MemCpyData memCpyData = { newData, m_Data, m_Size * sizeof(T) };
  52. // perform memcpy with GC lock held so GC doesn't see torn pointer values.I think this is less of an issue with Boehm than other GCs, but being safe.
  53. il2cpp::gc::GarbageCollector::CallWithAllocLockHeld(&CopyValues, &memCpyData);
  54. il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
  55. GarbageCollector::SetWriteBarrier((void**)newData, m_Size * sizeof(T));
  56. m_Size = newSize;
  57. m_Data = newData;
  58. IL2CPP_ASSERT(m_Data);
  59. }
  60. size_t index = m_Map.size();
  61. m_Map.insert(std::make_pair(k, index));
  62. m_Data[index] = value;
  63. GarbageCollector::SetWriteBarrier((void**)(m_Data + index));
  64. IL2CPP_ASSERT(m_Map.size() <= m_Size);
  65. return true;
  66. }
  67. bool TryGetValue(const Key& k, T* value)
  68. {
  69. ConstIterator iter = m_Map.find(k);
  70. if (iter == m_Map.end())
  71. return false;
  72. size_t index = iter->second;
  73. IL2CPP_ASSERT(index <= m_Map.size());
  74. *value = m_Data[index];
  75. return true;
  76. }
  77. private:
  78. struct MemCpyData
  79. {
  80. void* dst;
  81. const void* src;
  82. size_t size;
  83. };
  84. static void* CopyValues(void* arg)
  85. {
  86. MemCpyData* thisPtr = (MemCpyData*)arg;
  87. memcpy(thisPtr->dst, thisPtr->src, thisPtr->size);
  88. return NULL;
  89. }
  90. Il2CppHashMap<Key, size_t, HashFcn, EqualKey> m_Map;
  91. T* m_Data;
  92. size_t m_Size;
  93. };
  94. }
  95. }