Merge pull request #2890 from sivarv/master
[platform/upstream/coreclr.git] / src / vm / stringliteralmap.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5
6 /*============================================================
7 **
8 ** Header:  Map used for interning of string literals.
9 **
10 ===========================================================*/
11
12 #ifndef _STRINGLITERALMAP_H
13 #define _STRINGLITERALMAP_H
14
15 #include "vars.hpp"
16 #include "appdomain.hpp"
17 #include "eehash.h"
18 #include "eeconfig.h" // For OS pages size
19 #include "memorypool.h"
20
21
22 class StringLiteralEntry;
23 // Allocate 16 entries (approx size sizeof(StringLiteralEntry)*16)
24 #define MAX_ENTRIES_PER_CHUNK 16
25
26 STRINGREF AllocateStringObject(EEStringData *pStringData);
27
28 // Loader allocator specific string literal map.
29 class StringLiteralMap
30 {
31 public:
32     // Constructor and destructor.
33     StringLiteralMap();
34     ~StringLiteralMap();
35
36     // Initialization method.
37     void  Init();
38
39     size_t GetSize()
40     {
41         LIMITED_METHOD_CONTRACT;
42         return m_MemoryPool?m_MemoryPool->GetSize():0;
43     }
44
45     // Method to retrieve a string from the map.
46     STRINGREF *GetStringLiteral(EEStringData *pStringData, BOOL bAddIfNotFound, BOOL bAppDomainWontUnload);
47
48     // Method to explicitly intern a string object.
49     STRINGREF *GetInternedString(STRINGREF *pString, BOOL bAddIfNotFound, BOOL bAppDomainWontUnload);
50
51 private:
52     // Hash tables that maps a Unicode string to a COM+ string handle.
53     EEUnicodeStringLiteralHashTable    *m_StringToEntryHashTable;
54
55     // The memorypool for hash entries for this hash table.
56     MemoryPool                  *m_MemoryPool;
57 };
58
59 // Global string literal map.
60 class GlobalStringLiteralMap
61 {
62     // StringLiteralMap and StringLiteralEntry need to acquire the crst of the global string literal map.
63     friend class StringLiteralMap;
64     friend class StringLiteralEntry;
65
66 public:
67     // Constructor and destructor.
68     GlobalStringLiteralMap();
69     ~GlobalStringLiteralMap();
70
71     // Initialization method.
72     void Init();
73
74     // Method to retrieve a string from the map. Takes a precomputed hash (for perf).
75     StringLiteralEntry *GetStringLiteral(EEStringData *pStringData, DWORD dwHash, BOOL bAddIfNotFound);
76
77     // Method to explicitly intern a string object. Takes a precomputed hash (for perf).
78     StringLiteralEntry *GetInternedString(STRINGREF *pString, DWORD dwHash, BOOL bAddIfNotFound);
79
80     // Method to calculate the hash
81     DWORD GetHash(EEStringData* pData)
82     {
83         WRAPPER_NO_CONTRACT;
84         return m_StringToEntryHashTable->GetHash(pData);
85     }
86
87     // public method to retrieve m_HashTableCrstGlobal
88     Crst* GetHashTableCrstGlobal() 
89     {
90         LIMITED_METHOD_CONTRACT;
91         return &m_HashTableCrstGlobal;
92     }
93
94 private:    
95     // Helper method to add a string to the global string literal map.
96     StringLiteralEntry *AddStringLiteral(EEStringData *pStringData);
97
98     // Helper method to add an interned string.
99     StringLiteralEntry *AddInternedString(STRINGREF *pString);
100
101     // Called by StringLiteralEntry when its RefCount falls to 0.
102     void RemoveStringLiteralEntry(StringLiteralEntry *pEntry);
103     
104     // Hash tables that maps a Unicode string to a LiteralStringEntry.
105     EEUnicodeStringLiteralHashTable    *m_StringToEntryHashTable;
106
107     // The memorypool for hash entries for this hash table.
108     MemoryPool                  *m_MemoryPool;
109
110     // The hash table table critical section.  
111     // (the Global suffix is so that it is clear in context whether the global table is being locked 
112     // or the per app domain table is being locked.  Sometimes there was confusion in the code
113     // changing the name of the global one will avoid this problem and prevent copy/paste errors)
114     
115     Crst                        m_HashTableCrstGlobal;
116
117     // The large heap handle table.
118     LargeHeapHandleTable        m_LargeHeapHandleTable;
119
120 };
121
122 class StringLiteralEntryArray;
123
124 // Ref counted entry representing a string literal.
125 class StringLiteralEntry
126 {
127 private:
128     StringLiteralEntry(EEStringData *pStringData, STRINGREF *pStringObj)
129     : m_pStringObj(pStringObj), m_dwRefCount(1)
130 #ifdef _DEBUG
131       , m_bDeleted(FALSE)
132 #endif
133     {
134         LIMITED_METHOD_CONTRACT;
135     }
136 protected:
137     ~StringLiteralEntry()
138     {
139         CONTRACTL
140         {
141             NOTHROW;
142             GC_NOTRIGGER;
143             PRECONDITION(CheckPointer<void>(this));
144         }
145         CONTRACTL_END;
146     }
147
148 public:
149     void AddRef()
150     {
151         CONTRACTL
152         {
153             NOTHROW;
154             GC_NOTRIGGER;
155             PRECONDITION(CheckPointer<void>(this));
156             PRECONDITION((LONG)VolatileLoad(&m_dwRefCount) > 0);            
157             PRECONDITION(SystemDomain::GetGlobalStringLiteralMapNoCreate()->m_HashTableCrstGlobal.OwnedByCurrentThread());            
158         }
159         CONTRACTL_END;
160
161         _ASSERTE (!m_bDeleted);
162
163         // We will keep the item alive forever if the refcount overflowed
164         if ((LONG)VolatileLoad(&m_dwRefCount) < 0)
165             return;
166
167         VolatileStore(&m_dwRefCount, VolatileLoad(&m_dwRefCount) + 1);
168     }
169 #ifndef DACCESS_COMPILE
170     FORCEINLINE static void StaticRelease(StringLiteralEntry* pEntry)
171     {        
172         CONTRACTL
173         {
174             PRECONDITION(SystemDomain::GetGlobalStringLiteralMapNoCreate()->m_HashTableCrstGlobal.OwnedByCurrentThread());            
175         }
176         CONTRACTL_END;
177         
178         pEntry->Release();
179     }
180 #else
181     FORCEINLINE static void StaticRelease(StringLiteralEntry* /* pEntry */)
182     {
183         WRAPPER_NO_CONTRACT;
184         DacNotImpl();
185     }
186 #endif // DACCESS_COMPILE
187
188 #ifndef DACCESS_COMPILE
189     void Release()
190     {
191         CONTRACTL
192         {
193             NOTHROW;
194             GC_NOTRIGGER;
195             PRECONDITION(CheckPointer<void>(this));
196             PRECONDITION(VolatileLoad(&m_dwRefCount) > 0);
197             PRECONDITION(SystemDomain::GetGlobalStringLiteralMapNoCreate()->m_HashTableCrstGlobal.OwnedByCurrentThread());
198         }
199         CONTRACTL_END;
200
201         // We will keep the item alive forever if the refcount overflowed
202         if ((LONG)VolatileLoad(&m_dwRefCount) < 0)
203             return;
204
205         VolatileStore(&m_dwRefCount, VolatileLoad(&m_dwRefCount) - 1);
206         if (VolatileLoad(&m_dwRefCount) == 0)
207         {
208             _ASSERTE(SystemDomain::GetGlobalStringLiteralMapNoCreate());
209             SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this);
210             // Puts this entry in the free list
211             DeleteEntry (this);             
212         }
213     }
214 #endif // DACCESS_COMPILE
215     
216     LONG GetRefCount()
217     {
218         CONTRACTL
219         {
220             NOTHROW;
221             if(GetThread()){GC_NOTRIGGER;}else{DISABLED(GC_TRIGGERS);};
222             PRECONDITION(CheckPointer(this));
223         }
224         CONTRACTL_END;
225
226         _ASSERTE (!m_bDeleted);
227
228         return (VolatileLoad(&m_dwRefCount));
229     }
230
231     STRINGREF* GetStringObject()
232     {
233         CONTRACTL
234         {
235             NOTHROW;
236             if(GetThread()){GC_NOTRIGGER;}else{DISABLED(GC_TRIGGERS);};
237             PRECONDITION(CheckPointer(this));
238         }
239         CONTRACTL_END;
240         return m_pStringObj;
241     }
242
243     void GetStringData(EEStringData *pStringData)
244     {
245         CONTRACTL
246         {
247             NOTHROW;
248             if(GetThread()){GC_NOTRIGGER;}else{DISABLED(GC_TRIGGERS);};
249             MODE_COOPERATIVE;
250             PRECONDITION(CheckPointer(this));
251             PRECONDITION(CheckPointer(pStringData));
252         }
253         CONTRACTL_END;
254             
255         WCHAR *thisChars;
256         int thisLength;
257
258         ObjectToSTRINGREF(*(StringObject**)m_pStringObj)->RefInterpretGetStringValuesDangerousForGC(&thisChars, &thisLength);
259         pStringData->SetCharCount (thisLength); // thisLength is in WCHARs and that's what EEStringData's char count wants
260         pStringData->SetStringBuffer (thisChars);
261     }
262
263     static StringLiteralEntry *AllocateEntry(EEStringData *pStringData, STRINGREF *pStringObj);
264     static void DeleteEntry (StringLiteralEntry *pEntry);
265
266 private:
267     STRINGREF*                  m_pStringObj;
268     union
269     {
270         DWORD                       m_dwRefCount;
271         StringLiteralEntry         *m_pNext;
272     };
273
274 #ifdef _DEBUG
275     BOOL m_bDeleted;       
276 #endif
277
278     // The static lists below are protected by GetGlobalStringLiteralMap()->m_HashTableCrstGlobal
279     static StringLiteralEntryArray *s_EntryList; // always the first entry array in the chain. 
280     static DWORD                    s_UsedEntries;   // number of entries used up in the first array
281     static StringLiteralEntry      *s_FreeEntryList; // free list chained thru the arrays.
282 };
283
284 typedef Wrapper<StringLiteralEntry*,DoNothing,StringLiteralEntry::StaticRelease> StringLiteralEntryHolder; 
285
286 class StringLiteralEntryArray
287 {
288 public:
289     StringLiteralEntryArray *m_pNext;
290     BYTE                     m_Entries[MAX_ENTRIES_PER_CHUNK*sizeof(StringLiteralEntry)];
291 };
292
293 #endif // _STRINGLITERALMAP_H
294