String.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include "il2cpp-config.h"
  2. #include "gc/Allocator.h"
  3. #include "gc/GarbageCollector.h"
  4. #include "gc/GCHandle.h"
  5. #include "os/Atomic.h"
  6. #include "os/Mutex.h"
  7. #include "vm/Exception.h"
  8. #include "vm/String.h"
  9. #include "vm/Object.h"
  10. #include "vm/Profiler.h"
  11. #include "gc/AppendOnlyGCHashMap.h"
  12. #include "utils/StringUtils.h"
  13. #include <string>
  14. #include <memory.h>
  15. #include "il2cpp-class-internals.h"
  16. #include "il2cpp-object-internals.h"
  17. #include "Baselib.h"
  18. #include "Cpp/ReentrantLock.h"
  19. namespace il2cpp
  20. {
  21. namespace vm
  22. {
  23. static Il2CppString* s_EmptyString;
  24. void String::InitializeEmptyString(Il2CppClass* stringClass)
  25. {
  26. IL2CPP_ASSERT(s_EmptyString == NULL && "Empty string was already initialized");
  27. // size for string and null terminator
  28. s_EmptyString = static_cast<Il2CppString*>(gc::GarbageCollector::AllocateFixed(sizeof(Il2CppString) + 2, 0));
  29. s_EmptyString->object.klass = stringClass;
  30. s_EmptyString->length = 0;
  31. s_EmptyString->chars[0] = 0;
  32. }
  33. void String::CleanupEmptyString()
  34. {
  35. IL2CPP_ASSERT(s_EmptyString && "Empty string was not yet initialized");
  36. gc::GarbageCollector::FreeFixed(s_EmptyString);
  37. s_EmptyString = NULL;
  38. }
  39. Il2CppString* String::Empty()
  40. {
  41. IL2CPP_ASSERT(s_EmptyString && "Empty string was not yet initialized");
  42. return s_EmptyString;
  43. }
  44. int32_t String::GetHash(Il2CppString* str)
  45. {
  46. const Il2CppChar* p = utils::StringUtils::GetChars(str);
  47. int i, len = utils::StringUtils::GetLength(str);
  48. uint32_t h = 0;
  49. for (i = 0; i < len; i++)
  50. {
  51. h = (h << 5) - h + *p;
  52. p++;
  53. }
  54. return h;
  55. }
  56. Il2CppString* String::New(const char* str)
  57. {
  58. return NewLen(str, (uint32_t)strlen(str));
  59. }
  60. Il2CppString* String::NewWrapper(const char* str)
  61. {
  62. return New(str);
  63. }
  64. Il2CppString* String::NewLen(const char* str, uint32_t length)
  65. {
  66. UTF16String utf16Chars = il2cpp::utils::StringUtils::Utf8ToUtf16(str, length);
  67. return NewUtf16(utf16Chars.c_str(), (uint32_t)utf16Chars.length());
  68. }
  69. Il2CppString* String::NewUtf16(const Il2CppChar* text, int32_t len)
  70. {
  71. Il2CppString *s;
  72. s = NewSize(len);
  73. IL2CPP_ASSERT(s != NULL);
  74. memcpy(utils::StringUtils::GetChars(s), text, (size_t)len * 2);
  75. return s;
  76. }
  77. Il2CppString* String::NewUtf16(const utils::StringView<Il2CppChar>& text)
  78. {
  79. IL2CPP_ASSERT(text.Length() < static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
  80. return NewUtf16(text.Str(), static_cast<int32_t>(text.Length()));
  81. }
  82. Il2CppString* String::NewSize(int32_t len)
  83. {
  84. if (len == 0)
  85. return Empty();
  86. Il2CppString *s;
  87. IL2CPP_ASSERT(len >= 0);
  88. size_t size = (sizeof(Il2CppString) + (((size_t)len + 1) * 2));
  89. /* overflow ? can't fit it, can't allocate it! */
  90. if (static_cast<uint32_t>(len) > size)
  91. Exception::RaiseOutOfMemoryException();
  92. s = reinterpret_cast<Il2CppString*>(Object::AllocatePtrFree(size, il2cpp_defaults.string_class));
  93. s->length = len;
  94. #if NEED_TO_ZERO_PTRFREE
  95. s->chars[len] = 0;
  96. #endif
  97. #if IL2CPP_ENABLE_PROFILER
  98. if (Profiler::ProfileAllocations())
  99. Profiler::Allocation((Il2CppObject*)s, il2cpp_defaults.string_class);
  100. #endif
  101. return s;
  102. }
  103. struct InternedString
  104. {
  105. int32_t length;
  106. const Il2CppChar* chars;
  107. };
  108. class InternedStringHash
  109. {
  110. public:
  111. size_t operator()(const InternedString& ea) const
  112. {
  113. return utils::StringUtils::Hash(ea.chars, ea.length);
  114. }
  115. };
  116. class InternedStringCompare
  117. {
  118. public:
  119. bool operator()(const InternedString& ea, const InternedString& eb) const
  120. {
  121. return (ea.length == eb.length) && (0 == memcmp(ea.chars, eb.chars, sizeof(Il2CppChar) * ea.length));
  122. }
  123. };
  124. typedef il2cpp::gc::AppendOnlyGCHashMap<InternedString, Il2CppString*, InternedStringHash, InternedStringCompare> InternedStringMap;
  125. static InternedStringMap* s_InternedStringMap;
  126. Il2CppString* String::Intern(Il2CppString* str)
  127. {
  128. // allocate this at runtime since it uses GC allocator to keep managed strings alive and needs GC initialized
  129. if (s_InternedStringMap == NULL)
  130. {
  131. InternedStringMap* newMap = new InternedStringMap();
  132. if (os::Atomic::CompareExchangePointer<InternedStringMap>(&s_InternedStringMap, newMap, NULL) != NULL)
  133. delete newMap;
  134. }
  135. InternedString internedString = { str->length, str->chars };
  136. Il2CppString* value = NULL;
  137. if (s_InternedStringMap->TryGetValue(internedString, &value))
  138. return value;
  139. internedString.chars = utils::StringUtils::GetChars(str);
  140. return s_InternedStringMap->GetOrAdd(internedString, str);
  141. }
  142. Il2CppString* String::IsInterned(Il2CppString* str)
  143. {
  144. // if this is NULL, it means we have no interned strings
  145. if (s_InternedStringMap == NULL)
  146. return NULL;
  147. InternedString internedString = { str->length, str->chars };
  148. Il2CppString* value = NULL;
  149. if (s_InternedStringMap->TryGetValue(internedString, &value))
  150. return value;
  151. return NULL;
  152. }
  153. } /* namespace vm */
  154. } /* namespace il2cpp */