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 | // File: CeeSectionString.cpp |
6 | // |
7 | |
8 | // |
9 | // =========================================================================== |
10 | #include "stdafx.h" |
11 | |
12 | struct StringTableEntry { |
13 | ULONG m_hashId; |
14 | int m_offset; |
15 | StringTableEntry *m_next; |
16 | }; |
17 | |
18 | CeeSectionString::CeeSectionString(CCeeGen &ceeFile, CeeSectionImpl &impl) |
19 | : CeeSection(ceeFile, impl) |
20 | { |
21 | memset(stringTable, 0, sizeof(stringTable)); |
22 | } |
23 | |
24 | void CeeSectionString::deleteEntries(StringTableEntry *e) |
25 | { |
26 | if (!e) |
27 | return; |
28 | deleteEntries(e->m_next); |
29 | delete e; |
30 | } |
31 | |
32 | #ifdef RDATA_STATS |
33 | int CeeSectionString::dumpEntries(StringTableEntry *e) |
34 | { |
35 | if (!e) |
36 | return 0; |
37 | else { |
38 | printf(" HashId: %d, value: %S\n" , e->m_hashId, computOffset(e->m_offset)); |
39 | return dumpEntries(e->m_next) + 1; |
40 | } |
41 | } |
42 | |
43 | void CeeSectionString::dumpTable() |
44 | { |
45 | int sum = 0, count = 0; |
46 | for (int i=0; i < MaxRealEntries; i++) { |
47 | if (stringTable[i]) { |
48 | printf("Bucket %d\n" , i); |
49 | printf("Total size: %d\n\n" , |
50 | count = dumpEntries(stringTable[i])); |
51 | sum += count; |
52 | } |
53 | } |
54 | printf("Total number strings: %d\n\n" , sum); |
55 | } |
56 | #endif |
57 | |
58 | CeeSectionString::~CeeSectionString() |
59 | { |
60 | #ifdef RDATA_STATS |
61 | dumpTable(); |
62 | #endif |
63 | for (int i=0; i < MaxRealEntries; i++) |
64 | deleteEntries(stringTable[i]); |
65 | } |
66 | |
67 | StringTableEntry* CeeSectionString::createEntry(__in_z LPWSTR target, ULONG hashId) |
68 | { |
69 | StringTableEntry *entry = new StringTableEntry; |
70 | if (!entry) |
71 | return NULL; |
72 | entry->m_next = NULL; |
73 | entry->m_hashId = hashId; |
74 | entry->m_offset = dataLen(); |
75 | size_t len = (wcslen(target)+1) * sizeof(wchar_t); |
76 | if (len > ULONG_MAX) { |
77 | delete entry; |
78 | return NULL; |
79 | } |
80 | void *buf = getBlock((ULONG)len); |
81 | if (!buf) { |
82 | delete entry; |
83 | return NULL; |
84 | } |
85 | memcpy(buf, target, len); |
86 | return entry; |
87 | } |
88 | |
89 | // Searches through the linked list looking for a match on hashID. If |
90 | // multiple elements hash to the same value, a strcmp must be done to |
91 | // check for match. The goal is to have very large hashId space so that |
92 | // string compares are minimized |
93 | StringTableEntry *CeeSectionString::findStringInsert( |
94 | StringTableEntry *&head, __in_z LPWSTR target, ULONG hashId) |
95 | { |
96 | StringTableEntry *cur, *prev; |
97 | cur = prev = head; |
98 | while (cur && cur->m_hashId < hashId) { |
99 | prev = cur; |
100 | cur = cur->m_next; |
101 | } |
102 | while (cur && cur->m_hashId == hashId) { |
103 | if (wcscmp(target, (LPWSTR)(computePointer(cur->m_offset))) == 0) |
104 | return cur; |
105 | prev = cur; |
106 | cur = cur->m_next; |
107 | } |
108 | // didn't find in chain so insert at prev |
109 | StringTableEntry *entry = createEntry(target, hashId); |
110 | if (cur == head) { |
111 | head = entry; |
112 | entry->m_next = prev; |
113 | } else { |
114 | prev->m_next = entry; |
115 | entry->m_next = cur; |
116 | } |
117 | return entry; |
118 | } |
119 | |
120 | HRESULT CeeSectionString::getEmittedStringRef(__in_z LPWSTR target, StringRef *ref) |
121 | { |
122 | TESTANDRETURN(ref!=NULL, E_POINTER); |
123 | ULONG hashId = HashString(target) % MaxVirtualEntries; |
124 | ULONG bucketIndex = hashId / MaxRealEntries; |
125 | |
126 | StringTableEntry *entry; |
127 | entry = findStringInsert(stringTable[bucketIndex], target, hashId); |
128 | |
129 | if (! entry) |
130 | return E_OUTOFMEMORY; |
131 | *ref = entry->m_offset; |
132 | return S_OK; |
133 | } |
134 | |