Bug 1739761 - arena-allocate strings in hunspell. r=glandium

This reduces the number of wasm pages allocated from 64 to 47 on en_us
builds, corresponding to about 1 MB of reduced memory usage.

Differential Revision: https://phabricator.services.mozilla.com/D132519
This commit is contained in:
Bobby Holley 2021-12-02 01:21:14 +00:00
Родитель cf11e2e94d
Коммит 031f81a28e
4 изменённых файлов: 402 добавлений и 36 удалений

Просмотреть файл

@ -0,0 +1,322 @@
diff --git a/extensions/spellcheck/hunspell/src/hashmgr.cxx b/extensions/spellcheck/hunspell/src/hashmgr.cxx
index 7e843c3e76624..9536880c9050d 100644
--- a/extensions/spellcheck/hunspell/src/hashmgr.cxx
+++ b/extensions/spellcheck/hunspell/src/hashmgr.cxx
@@ -68,6 +68,7 @@
* SUCH DAMAGE.
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -123,8 +124,8 @@ HashMgr::~HashMgr() {
nt = pt->next;
if (pt->astr &&
(!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen)))
- free(pt->astr);
- free(pt);
+ arena_free(pt->astr);
+ arena_free(pt);
pt = nt;
}
}
@@ -134,18 +135,18 @@ HashMgr::~HashMgr() {
if (aliasf) {
for (int j = 0; j < (numaliasf); j++)
- free(aliasf[j]);
- free(aliasf);
+ arena_free(aliasf[j]);
+ arena_free(aliasf);
aliasf = NULL;
if (aliasflen) {
- free(aliasflen);
+ arena_free(aliasflen);
aliasflen = NULL;
}
}
if (aliasm) {
for (int j = 0; j < (numaliasm); j++)
- free(aliasm[j]);
- free(aliasm);
+ arena_free(aliasm[j]);
+ arena_free(aliasm);
aliasm = NULL;
}
@@ -159,6 +160,8 @@ HashMgr::~HashMgr() {
#ifdef MOZILLA_CLIENT
delete[] csconv;
#endif
+
+ assert(outstanding_arena_allocations == 0);
}
// lookup a root word in the hashtable
@@ -227,7 +230,7 @@ int HashMgr::add_word(const std::string& in_word,
int descl = desc ? (aliasm ? sizeof(char*) : desc->size() + 1) : 0;
// variable-length hash record with word and optional fields
struct hentry* hp =
- (struct hentry*)malloc(sizeof(struct hentry) + word->size() + descl);
+ (struct hentry*)arena_alloc(sizeof(struct hentry) + word->size() + descl);
if (!hp) {
delete desc_copy;
delete word_copy;
@@ -371,10 +374,10 @@ int HashMgr::add_word(const std::string& in_word,
// remove hidden onlyupcase homonym
if (!onlyupcase) {
if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
- free(dp->astr);
+ arena_free(dp->astr);
dp->astr = hp->astr;
dp->alen = hp->alen;
- free(hp);
+ arena_free(hp);
delete desc_copy;
delete word_copy;
return 0;
@@ -391,10 +394,10 @@ int HashMgr::add_word(const std::string& in_word,
// remove hidden onlyupcase homonym
if (!onlyupcase) {
if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
- free(dp->astr);
+ arena_free(dp->astr);
dp->astr = hp->astr;
dp->alen = hp->alen;
- free(hp);
+ arena_free(hp);
delete desc_copy;
delete word_copy;
return 0;
@@ -410,8 +413,8 @@ int HashMgr::add_word(const std::string& in_word,
} else {
// remove hidden onlyupcase homonym
if (hp->astr)
- free(hp->astr);
- free(hp);
+ arena_free(hp->astr);
+ arena_free(hp);
}
delete desc_copy;
@@ -435,7 +438,7 @@ int HashMgr::add_hidden_capitalized_word(const std::string& word,
((captype == ALLCAP) && (flagslen != 0))) &&
!((flagslen != 0) && TESTAFF(flags, forbiddenword, flagslen))) {
unsigned short* flags2 =
- (unsigned short*)malloc(sizeof(unsigned short) * (flagslen + 1));
+ (unsigned short*)arena_alloc(sizeof(unsigned short) * (flagslen + 1));
if (!flags2)
return 1;
if (flagslen)
@@ -484,13 +487,13 @@ int HashMgr::remove(const std::string& word) {
while (dp) {
if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) {
unsigned short* flags =
- (unsigned short*)malloc(sizeof(unsigned short) * (dp->alen + 1));
+ (unsigned short*)arena_alloc(sizeof(unsigned short) * (dp->alen + 1));
if (!flags)
return 1;
for (int i = 0; i < dp->alen; i++)
flags[i] = dp->astr[i];
flags[dp->alen] = forbiddenword;
- free(dp->astr);
+ arena_free(dp->astr);
dp->astr = flags;
dp->alen++;
std::sort(flags, flags + dp->alen);
@@ -538,7 +541,7 @@ int HashMgr::add_with_affix(const std::string& word, const std::string& example)
add_word(word, wcl, dp->astr, dp->alen, NULL, false, captype);
} else {
unsigned short* flags =
- (unsigned short*)malloc(dp->alen * sizeof(unsigned short));
+ (unsigned short*) arena_alloc(dp->alen * sizeof(unsigned short));
if (flags) {
memcpy((void*)flags, (void*)dp->astr,
dp->alen * sizeof(unsigned short));
@@ -727,7 +730,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n",
af->getlinenum());
len /= 2;
- *result = (unsigned short*)malloc(len * sizeof(unsigned short));
+ *result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
for (int i = 0; i < len; i++) {
@@ -744,7 +747,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
if (flags[i] == ',')
len++;
}
- *result = (unsigned short*)malloc(len * sizeof(unsigned short));
+ *result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
dest = *result;
@@ -779,7 +782,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
std::vector<w_char> w;
u8_u16(w, flags);
len = w.size();
- *result = (unsigned short*)malloc(len * sizeof(unsigned short));
+ *result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
memcpy(*result, &w[0], len * sizeof(short));
@@ -788,7 +791,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
default: { // Ispell's one-character flags (erfg -> e r f g)
unsigned short* dest;
len = flags.size();
- *result = (unsigned short*)malloc(len * sizeof(unsigned short));
+ *result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
dest = *result;
@@ -1075,15 +1078,15 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
return false;
}
aliasf =
- (unsigned short**)malloc(numaliasf * sizeof(unsigned short*));
+ (unsigned short**)arena_alloc(numaliasf * sizeof(unsigned short*));
aliasflen =
- (unsigned short*)malloc(numaliasf * sizeof(unsigned short));
+ (unsigned short*)arena_alloc(numaliasf * sizeof(unsigned short));
if (!aliasf || !aliasflen) {
numaliasf = 0;
if (aliasf)
- free(aliasf);
+ arena_free(aliasf);
if (aliasflen)
- free(aliasflen);
+ arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
return false;
@@ -1099,8 +1102,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
}
if (np != 2) {
numaliasf = 0;
- free(aliasf);
- free(aliasflen);
+ arena_free(aliasf);
+ arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
@@ -1124,8 +1127,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
case 0: {
if (nl.compare(start_piece - nl.begin(), 2, "AF", 2) != 0) {
numaliasf = 0;
- free(aliasf);
- free(aliasflen);
+ arena_free(aliasf);
+ arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
@@ -1148,8 +1151,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
start_piece = mystrsep(nl, iter);
}
if (!aliasf[j]) {
- free(aliasf);
- free(aliasflen);
+ arena_free(aliasf);
+ arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
numaliasf = 0;
@@ -1200,7 +1203,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
af->getlinenum());
return false;
}
- aliasm = (char**)malloc(numaliasm * sizeof(char*));
+ aliasm = (char**)arena_alloc(numaliasm * sizeof(char*));
if (!aliasm) {
numaliasm = 0;
return false;
@@ -1216,7 +1219,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
}
if (np != 2) {
numaliasm = 0;
- free(aliasm);
+ arena_free(aliasm);
aliasm = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
af->getlinenum());
@@ -1240,7 +1243,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
af->getlinenum());
numaliasm = 0;
- free(aliasm);
+ arena_free(aliasm);
aliasm = NULL;
return false;
}
@@ -1267,7 +1270,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
}
if (!aliasm[j]) {
numaliasm = 0;
- free(aliasm);
+ arena_free(aliasm);
aliasm = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
af->getlinenum());
@@ -1387,3 +1390,25 @@ bool HashMgr::parse_reptable(const std::string& line, FileMgr* af) {
const std::vector<replentry>& HashMgr::get_reptable() const {
return reptable;
}
+
+void* HashMgr::arena_alloc(int num_bytes) {
+ if (num_bytes > CHUNK_SIZE) {
+ assert(false);
+ return nullptr;
+ }
+
+ if (arena.empty() || (CHUNK_SIZE - current_chunk_offset < num_bytes)) {
+ arena.push_back(std::make_unique<uint8_t[]>(CHUNK_SIZE));
+ current_chunk_offset = 0;
+ }
+
+ uint8_t* ptr = &arena.back()[current_chunk_offset];
+ current_chunk_offset += num_bytes;
+ outstanding_arena_allocations++;
+ return ptr;
+}
+
+void HashMgr::arena_free(void* ptr) {
+ --outstanding_arena_allocations;
+ assert(outstanding_arena_allocations >= 0);
+}
diff --git a/extensions/spellcheck/hunspell/src/hashmgr.hxx b/extensions/spellcheck/hunspell/src/hashmgr.hxx
index b6eadddecc5b9..6919bc725b885 100644
--- a/extensions/spellcheck/hunspell/src/hashmgr.hxx
+++ b/extensions/spellcheck/hunspell/src/hashmgr.hxx
@@ -72,6 +72,7 @@
#define HASHMGR_HXX_
#include <stdio.h>
+#include <memory>
#include <string>
#include <vector>
@@ -153,6 +154,22 @@ class HashMgr {
bool parse_aliasm(const std::string& line, FileMgr* af);
bool parse_reptable(const std::string& line, FileMgr* af);
int remove_forbidden_flag(const std::string& word);
+
+ // Our Mozilla fork uses a simple arena allocator for certain strings which
+ // persist for the lifetime of the HashMgr in order to avoid heap fragmentation.
+ // It's a simple bump-allocator, so we can't actually free() memory midway
+ // through the lifecycle, but we have a dummy free() implementation to ensure
+ // that our calls to arena_alloc() and arena_free() are balanced.
+ void* arena_alloc(int num_bytes);
+ void* arena_alloc(int num_bytes) const {
+ return const_cast<HashMgr*>(this)->arena_alloc(num_bytes);
+ }
+ void arena_free(void* ptr);
+
+ static const int CHUNK_SIZE = 4096;
+ std::vector<std::unique_ptr<uint8_t[]>> arena;
+ int current_chunk_offset = 0;
+ int outstanding_arena_allocations = 0;
};
#endif

Просмотреть файл

@ -68,6 +68,7 @@
* SUCH DAMAGE.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@ -123,8 +124,8 @@ HashMgr::~HashMgr() {
nt = pt->next;
if (pt->astr &&
(!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen)))
free(pt->astr);
free(pt);
arena_free(pt->astr);
arena_free(pt);
pt = nt;
}
}
@ -134,18 +135,18 @@ HashMgr::~HashMgr() {
if (aliasf) {
for (int j = 0; j < (numaliasf); j++)
free(aliasf[j]);
free(aliasf);
arena_free(aliasf[j]);
arena_free(aliasf);
aliasf = NULL;
if (aliasflen) {
free(aliasflen);
arena_free(aliasflen);
aliasflen = NULL;
}
}
if (aliasm) {
for (int j = 0; j < (numaliasm); j++)
free(aliasm[j]);
free(aliasm);
arena_free(aliasm[j]);
arena_free(aliasm);
aliasm = NULL;
}
@ -159,6 +160,8 @@ HashMgr::~HashMgr() {
#ifdef MOZILLA_CLIENT
delete[] csconv;
#endif
assert(outstanding_arena_allocations == 0);
}
// lookup a root word in the hashtable
@ -227,7 +230,7 @@ int HashMgr::add_word(const std::string& in_word,
int descl = desc ? (aliasm ? sizeof(char*) : desc->size() + 1) : 0;
// variable-length hash record with word and optional fields
struct hentry* hp =
(struct hentry*)malloc(sizeof(struct hentry) + word->size() + descl);
(struct hentry*)arena_alloc(sizeof(struct hentry) + word->size() + descl);
if (!hp) {
delete desc_copy;
delete word_copy;
@ -371,10 +374,10 @@ int HashMgr::add_word(const std::string& in_word,
// remove hidden onlyupcase homonym
if (!onlyupcase) {
if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
free(dp->astr);
arena_free(dp->astr);
dp->astr = hp->astr;
dp->alen = hp->alen;
free(hp);
arena_free(hp);
delete desc_copy;
delete word_copy;
return 0;
@ -391,10 +394,10 @@ int HashMgr::add_word(const std::string& in_word,
// remove hidden onlyupcase homonym
if (!onlyupcase) {
if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
free(dp->astr);
arena_free(dp->astr);
dp->astr = hp->astr;
dp->alen = hp->alen;
free(hp);
arena_free(hp);
delete desc_copy;
delete word_copy;
return 0;
@ -410,8 +413,8 @@ int HashMgr::add_word(const std::string& in_word,
} else {
// remove hidden onlyupcase homonym
if (hp->astr)
free(hp->astr);
free(hp);
arena_free(hp->astr);
arena_free(hp);
}
delete desc_copy;
@ -435,7 +438,7 @@ int HashMgr::add_hidden_capitalized_word(const std::string& word,
((captype == ALLCAP) && (flagslen != 0))) &&
!((flagslen != 0) && TESTAFF(flags, forbiddenword, flagslen))) {
unsigned short* flags2 =
(unsigned short*)malloc(sizeof(unsigned short) * (flagslen + 1));
(unsigned short*)arena_alloc(sizeof(unsigned short) * (flagslen + 1));
if (!flags2)
return 1;
if (flagslen)
@ -484,13 +487,13 @@ int HashMgr::remove(const std::string& word) {
while (dp) {
if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) {
unsigned short* flags =
(unsigned short*)malloc(sizeof(unsigned short) * (dp->alen + 1));
(unsigned short*)arena_alloc(sizeof(unsigned short) * (dp->alen + 1));
if (!flags)
return 1;
for (int i = 0; i < dp->alen; i++)
flags[i] = dp->astr[i];
flags[dp->alen] = forbiddenword;
free(dp->astr);
arena_free(dp->astr);
dp->astr = flags;
dp->alen++;
std::sort(flags, flags + dp->alen);
@ -538,7 +541,7 @@ int HashMgr::add_with_affix(const std::string& word, const std::string& example)
add_word(word, wcl, dp->astr, dp->alen, NULL, false, captype);
} else {
unsigned short* flags =
(unsigned short*)malloc(dp->alen * sizeof(unsigned short));
(unsigned short*) arena_alloc(dp->alen * sizeof(unsigned short));
if (flags) {
memcpy((void*)flags, (void*)dp->astr,
dp->alen * sizeof(unsigned short));
@ -727,7 +730,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n",
af->getlinenum());
len /= 2;
*result = (unsigned short*)malloc(len * sizeof(unsigned short));
*result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
for (int i = 0; i < len; i++) {
@ -744,7 +747,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
if (flags[i] == ',')
len++;
}
*result = (unsigned short*)malloc(len * sizeof(unsigned short));
*result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
dest = *result;
@ -779,7 +782,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
std::vector<w_char> w;
u8_u16(w, flags);
len = w.size();
*result = (unsigned short*)malloc(len * sizeof(unsigned short));
*result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
memcpy(*result, &w[0], len * sizeof(short));
@ -788,7 +791,7 @@ int HashMgr::decode_flags(unsigned short** result, const std::string& flags, Fil
default: { // Ispell's one-character flags (erfg -> e r f g)
unsigned short* dest;
len = flags.size();
*result = (unsigned short*)malloc(len * sizeof(unsigned short));
*result = (unsigned short*)arena_alloc(len * sizeof(unsigned short));
if (!*result)
return -1;
dest = *result;
@ -1075,15 +1078,15 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
return false;
}
aliasf =
(unsigned short**)malloc(numaliasf * sizeof(unsigned short*));
(unsigned short**)arena_alloc(numaliasf * sizeof(unsigned short*));
aliasflen =
(unsigned short*)malloc(numaliasf * sizeof(unsigned short));
(unsigned short*)arena_alloc(numaliasf * sizeof(unsigned short));
if (!aliasf || !aliasflen) {
numaliasf = 0;
if (aliasf)
free(aliasf);
arena_free(aliasf);
if (aliasflen)
free(aliasflen);
arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
return false;
@ -1099,8 +1102,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
}
if (np != 2) {
numaliasf = 0;
free(aliasf);
free(aliasflen);
arena_free(aliasf);
arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
@ -1124,8 +1127,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
case 0: {
if (nl.compare(start_piece - nl.begin(), 2, "AF", 2) != 0) {
numaliasf = 0;
free(aliasf);
free(aliasflen);
arena_free(aliasf);
arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
@ -1148,8 +1151,8 @@ bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
start_piece = mystrsep(nl, iter);
}
if (!aliasf[j]) {
free(aliasf);
free(aliasflen);
arena_free(aliasf);
arena_free(aliasflen);
aliasf = NULL;
aliasflen = NULL;
numaliasf = 0;
@ -1200,7 +1203,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
af->getlinenum());
return false;
}
aliasm = (char**)malloc(numaliasm * sizeof(char*));
aliasm = (char**)arena_alloc(numaliasm * sizeof(char*));
if (!aliasm) {
numaliasm = 0;
return false;
@ -1216,7 +1219,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
}
if (np != 2) {
numaliasm = 0;
free(aliasm);
arena_free(aliasm);
aliasm = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
af->getlinenum());
@ -1240,7 +1243,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
af->getlinenum());
numaliasm = 0;
free(aliasm);
arena_free(aliasm);
aliasm = NULL;
return false;
}
@ -1267,7 +1270,7 @@ bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
}
if (!aliasm[j]) {
numaliasm = 0;
free(aliasm);
arena_free(aliasm);
aliasm = NULL;
HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
af->getlinenum());
@ -1387,3 +1390,25 @@ bool HashMgr::parse_reptable(const std::string& line, FileMgr* af) {
const std::vector<replentry>& HashMgr::get_reptable() const {
return reptable;
}
void* HashMgr::arena_alloc(int num_bytes) {
if (num_bytes > CHUNK_SIZE) {
assert(false);
return nullptr;
}
if (arena.empty() || (CHUNK_SIZE - current_chunk_offset < num_bytes)) {
arena.push_back(std::make_unique<uint8_t[]>(CHUNK_SIZE));
current_chunk_offset = 0;
}
uint8_t* ptr = &arena.back()[current_chunk_offset];
current_chunk_offset += num_bytes;
outstanding_arena_allocations++;
return ptr;
}
void HashMgr::arena_free(void* ptr) {
--outstanding_arena_allocations;
assert(outstanding_arena_allocations >= 0);
}

Просмотреть файл

@ -72,6 +72,8 @@
#define HASHMGR_HXX_
#include <stdio.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
@ -153,6 +155,22 @@ class HashMgr {
bool parse_aliasm(const std::string& line, FileMgr* af);
bool parse_reptable(const std::string& line, FileMgr* af);
int remove_forbidden_flag(const std::string& word);
// Our Mozilla fork uses a simple arena allocator for certain strings which
// persist for the lifetime of the HashMgr in order to avoid heap fragmentation.
// It's a simple bump-allocator, so we can't actually free() memory midway
// through the lifecycle, but we have a dummy free() implementation to ensure
// that our calls to arena_alloc() and arena_free() are balanced.
void* arena_alloc(int num_bytes);
void* arena_alloc(int num_bytes) const {
return const_cast<HashMgr*>(this)->arena_alloc(num_bytes);
}
void arena_free(void* ptr);
static const int CHUNK_SIZE = 4096;
std::vector<std::unique_ptr<uint8_t[]>> arena;
int current_chunk_offset = 0;
int outstanding_arena_allocations = 0;
};
#endif

Просмотреть файл

@ -28,3 +28,4 @@ rm -rf ${tmpclonedir}
cd ${hunspell_dir}/src
patch -p5 < ../patches/bug1410214.patch
patch -p5 < ../patches/bug1739761.patch