AppendOnlyGCHashMap.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #pragma once
  2. #include "utils/Il2CppHashMap.h"
  3. #include "utils/NonCopyable.h"
  4. #include "GarbageCollector.h"
  5. #include "os/FastReaderReaderWriterLock.h"
  6. namespace il2cpp
  7. {
  8. namespace gc
  9. {
  10. template<class Key, class T,
  11. class HashFcn,
  12. class EqualKey = std::equal_to<Key> >
  13. class AppendOnlyGCHashMap : public il2cpp::utils::NonCopyable
  14. {
  15. typedef Il2CppHashMap<Key, size_t, HashFcn, EqualKey> hash_map_type;
  16. typedef typename Il2CppHashMap<Key, size_t, HashFcn, EqualKey>::const_iterator ConstIterator;
  17. public:
  18. typedef typename hash_map_type::key_type key_type;
  19. typedef T data_type;
  20. typedef typename hash_map_type::size_type size_type;
  21. typedef typename hash_map_type::hasher hasher;
  22. typedef typename hash_map_type::key_equal key_equal;
  23. AppendOnlyGCHashMap() :
  24. m_Data(NULL),
  25. m_Size(0)
  26. {
  27. }
  28. ~AppendOnlyGCHashMap()
  29. {
  30. if (m_Data)
  31. il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
  32. }
  33. bool Contains(const Key& k)
  34. {
  35. os::FastReaderReaderWriterAutoSharedLock readLock(&lock);
  36. return m_Map.find(k) != m_Map.end();
  37. }
  38. // Returns the existing value if the it was already added or inserts and returns value
  39. T GetOrAdd(const Key& k, T value)
  40. {
  41. os::FastReaderReaderWriterAutoExclusiveLock writeLock(&lock);
  42. ConstIterator iter = m_Map.find(k);
  43. if (iter != m_Map.end())
  44. {
  45. size_t index = iter->second;
  46. IL2CPP_ASSERT(index <= m_Map.size());
  47. return m_Data[index];
  48. }
  49. if (m_Size == 0)
  50. {
  51. m_Size = 8;
  52. m_Data = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(m_Size * sizeof(T), NULL);
  53. IL2CPP_ASSERT(m_Data);
  54. }
  55. else if (m_Map.size() == m_Size)
  56. {
  57. size_t newSize = 2 * m_Size;
  58. T* newData = (T*)il2cpp::gc::GarbageCollector::AllocateFixed(newSize * sizeof(T), NULL);
  59. MemCpyData memCpyData = { newData, m_Data, m_Size * sizeof(T) };
  60. // 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.
  61. il2cpp::gc::GarbageCollector::CallWithAllocLockHeld(&CopyValues, &memCpyData);
  62. il2cpp::gc::GarbageCollector::FreeFixed(m_Data);
  63. GarbageCollector::SetWriteBarrier((void**)newData, m_Size * sizeof(T));
  64. m_Size = newSize;
  65. m_Data = newData;
  66. IL2CPP_ASSERT(m_Data);
  67. }
  68. size_t index = m_Map.size();
  69. m_Map.insert(std::make_pair(k, index));
  70. m_Data[index] = value;
  71. GarbageCollector::SetWriteBarrier((void**)(m_Data + index));
  72. IL2CPP_ASSERT(m_Map.size() <= m_Size);
  73. return value;
  74. }
  75. void Add(const Key& k, T value)
  76. {
  77. GetOrAdd(k, value);
  78. }
  79. bool TryGetValue(const Key& k, T* value)
  80. {
  81. os::FastReaderReaderWriterAutoSharedLock readLock(&lock);
  82. ConstIterator iter = m_Map.find(k);
  83. if (iter == m_Map.end())
  84. return false;
  85. size_t index = iter->second;
  86. IL2CPP_ASSERT(index <= m_Map.size());
  87. *value = m_Data[index];
  88. return true;
  89. }
  90. private:
  91. struct MemCpyData
  92. {
  93. void* dst;
  94. const void* src;
  95. size_t size;
  96. };
  97. static void* CopyValues(void* arg)
  98. {
  99. MemCpyData* thisPtr = (MemCpyData*)arg;
  100. memcpy(thisPtr->dst, thisPtr->src, thisPtr->size);
  101. return NULL;
  102. }
  103. Il2CppHashMap<Key, size_t, HashFcn, EqualKey> m_Map;
  104. T* m_Data;
  105. size_t m_Size;
  106. os::FastReaderReaderWriterLock lock;
  107. };
  108. }
  109. }