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
12struct StringTableEntry {
13 ULONG m_hashId;
14 int m_offset;
15 StringTableEntry *m_next;
16};
17
18CeeSectionString::CeeSectionString(CCeeGen &ceeFile, CeeSectionImpl &impl)
19 : CeeSection(ceeFile, impl)
20{
21 memset(stringTable, 0, sizeof(stringTable));
22}
23
24void CeeSectionString::deleteEntries(StringTableEntry *e)
25{
26 if (!e)
27 return;
28 deleteEntries(e->m_next);
29 delete e;
30}
31
32#ifdef RDATA_STATS
33int 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
43void 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
58CeeSectionString::~CeeSectionString()
59{
60#ifdef RDATA_STATS
61 dumpTable();
62#endif
63 for (int i=0; i < MaxRealEntries; i++)
64 deleteEntries(stringTable[i]);
65}
66
67StringTableEntry* 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
93StringTableEntry *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
120HRESULT 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