Skip to content

Commit 813cd6e

Browse files
authored
Merge pull request #17306 from JuliaLang/yyc/gc/perm
Simple perm gen allocator
2 parents 55da4b1 + 9f44a40 commit 813cd6e

File tree

7 files changed

+76
-42
lines changed

7 files changed

+76
-42
lines changed

src/alloc.c

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -645,17 +645,13 @@ jl_method_t *jl_new_method(jl_lambda_info_t *definition, jl_sym_t *name, jl_tupl
645645

646646
// symbols --------------------------------------------------------------------
647647

648-
static jl_mutex_t symbol_table_lock;
649-
650648
static jl_sym_t *volatile symtab = NULL;
651649

652650
static uintptr_t hash_symbol(const char *str, size_t len)
653651
{
654652
return memhash(str, len) ^ ~(uintptr_t)0/3*2;
655653
}
656654

657-
#define SYM_POOL_SIZE 524288
658-
659655
static size_t symbol_nbytes(size_t len)
660656
{
661657
return (sizeof(jl_taggedvalue_t) + sizeof(jl_sym_t) + len + 1 + 7) & -8;
@@ -666,23 +662,7 @@ static jl_sym_t *mk_symbol(const char *str, size_t len)
666662
jl_sym_t *sym;
667663
size_t nb = symbol_nbytes(len);
668664

669-
if (nb >= SYM_POOL_SIZE) {
670-
jl_exceptionf(jl_argumenterror_type, "Symbol length exceeds maximum length");
671-
}
672-
673-
jl_taggedvalue_t *tag;
674-
#ifdef MEMDEBUG
675-
tag = (jl_taggedvalue_t*)malloc(nb);
676-
#else
677-
static char *sym_pool = NULL;
678-
static char *pool_ptr = NULL;
679-
if (sym_pool == NULL || pool_ptr+nb > sym_pool+SYM_POOL_SIZE) {
680-
sym_pool = (char*)malloc(SYM_POOL_SIZE);
681-
pool_ptr = sym_pool;
682-
}
683-
tag = (jl_taggedvalue_t*)pool_ptr;
684-
pool_ptr += nb;
685-
#endif
665+
jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc_nolock(nb);
686666
sym = (jl_sym_t*)jl_valueof(tag);
687667
// set to old marked since we don't need write barrier on it.
688668
tag->header = ((uintptr_t)jl_sym_type) | GC_OLD_MARKED;
@@ -726,15 +706,15 @@ static jl_sym_t *_jl_symbol(const char *str, size_t len)
726706
jl_sym_t *volatile *slot;
727707
jl_sym_t *node = symtab_lookup(&symtab, str, len, &slot);
728708
if (node == NULL) {
729-
JL_LOCK(&symbol_table_lock); // Might GC
709+
JL_LOCK_NOGC(&gc_perm_lock);
730710
// Someone might have updated it, check and look up again
731711
if (*slot != NULL && (node = symtab_lookup(slot, str, len, &slot))) {
732-
JL_UNLOCK(&symbol_table_lock); // Might GC
712+
JL_UNLOCK_NOGC(&gc_perm_lock);
733713
return node;
734714
}
735715
node = mk_symbol(str, len);
736716
jl_atomic_store_release(slot, node);
737-
JL_UNLOCK(&symbol_table_lock); // Might GC
717+
JL_UNLOCK_NOGC(&gc_perm_lock);
738718
}
739719
return node;
740720
}
@@ -778,8 +758,6 @@ JL_DLLEXPORT jl_sym_t *jl_gensym(void)
778758
JL_DLLEXPORT jl_sym_t *jl_tagged_gensym(const char *str, int32_t len)
779759
{
780760
char gs_name[14];
781-
if (symbol_nbytes(len) >= SYM_POOL_SIZE)
782-
jl_exceptionf(jl_argumenterror_type, "Symbol length exceeds maximum");
783761
if (memchr(str, 0, len))
784762
jl_exceptionf(jl_argumenterror_type, "Symbol name may not contain \\0");
785763
char *name = (char*) (len >= 256 ? malloc(sizeof(gs_name)+len+3) :
@@ -872,7 +850,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
872850
return t;
873851
}
874852

875-
static struct _jl_datatype_layout_t *jl_get_layout(
853+
static jl_datatype_layout_t *jl_get_layout(
876854
uint32_t nfields,
877855
uint32_t alignment,
878856
int haspadding,
@@ -903,8 +881,8 @@ static struct _jl_datatype_layout_t *jl_get_layout(
903881

904882
// allocate a new descriptor
905883
uint32_t fielddesc_size = jl_fielddesc_size(fielddesc_type);
906-
struct _jl_datatype_layout_t *flddesc = (struct _jl_datatype_layout_t*)malloc(
907-
sizeof(struct _jl_datatype_layout_t) + nfields * fielddesc_size);
884+
jl_datatype_layout_t *flddesc = (jl_datatype_layout_t*)jl_gc_perm_alloc(
885+
sizeof(jl_datatype_layout_t) + nfields * fielddesc_size);
908886
flddesc->nfields = nfields;
909887
flddesc->alignment = alignment;
910888
flddesc->haspadding = haspadding;

src/dump.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,8 +1225,8 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc)
12251225
uint16_t nf = read_uint16(s);
12261226
uint8_t fielddesc_type = read_int8(s);
12271227
size_t fielddesc_size = nf > 0 ? jl_fielddesc_size(fielddesc_type) : 0;
1228-
struct _jl_datatype_layout_t *layout = (struct _jl_datatype_layout_t*)malloc(
1229-
sizeof(struct _jl_datatype_layout_t) + nf * fielddesc_size);
1228+
jl_datatype_layout_t *layout = (jl_datatype_layout_t*)jl_gc_perm_alloc(
1229+
sizeof(jl_datatype_layout_t) + nf * fielddesc_size);
12301230
layout->nfields = nf;
12311231
layout->fielddesc_type = fielddesc_type;
12321232
layout->alignment = read_int32(s);

src/gc.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,6 +2031,61 @@ JL_DLLEXPORT void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz,
20312031
return b;
20322032
}
20332033

2034+
// Perm gen allocator
2035+
// 2M pool
2036+
#define GC_PERM_POOL_SIZE (2 * 1024 * 1024)
2037+
// 20k limit for pool allocation. At most 1% fragmentation
2038+
#define GC_PERM_POOL_LIMIT (20 * 1024)
2039+
jl_mutex_t gc_perm_lock = {0, 0};
2040+
static char *gc_perm_pool = NULL;
2041+
static size_t gc_perm_size = 0;
2042+
2043+
// **NOT** a safepoint
2044+
void *jl_gc_perm_alloc_nolock(size_t sz)
2045+
{
2046+
// The caller should have acquired `gc_perm_lock`
2047+
#ifndef MEMDEBUG
2048+
if (__unlikely(sz > GC_PERM_POOL_LIMIT))
2049+
#endif
2050+
return malloc(sz);
2051+
sz = LLT_ALIGN(sz, JL_SMALL_BYTE_ALIGNMENT);
2052+
if (__unlikely(sz > gc_perm_size)) {
2053+
#ifdef _OS_WINDOWS_
2054+
void *pool = VirtualAlloc(NULL,
2055+
GC_PERM_POOL_SIZE + JL_SMALL_BYTE_ALIGNMENT,
2056+
MEM_COMMIT, PAGE_READWRITE);
2057+
if (__unlikely(pool == NULL))
2058+
return NULL;
2059+
pool = (void*)LLT_ALIGN((uintptr_t)pool, JL_SMALL_BYTE_ALIGNMENT);
2060+
#else
2061+
void *pool = mmap(0, GC_PERM_POOL_SIZE, PROT_READ | PROT_WRITE,
2062+
MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
2063+
if (__unlikely(pool == MAP_FAILED))
2064+
return NULL;
2065+
#endif
2066+
gc_perm_pool = (char*)pool;
2067+
gc_perm_size = GC_PERM_POOL_SIZE;
2068+
}
2069+
assert(((uintptr_t)gc_perm_pool) % JL_SMALL_BYTE_ALIGNMENT == 0);
2070+
void *p = gc_perm_pool;
2071+
gc_perm_size -= sz;
2072+
gc_perm_pool += sz;
2073+
return p;
2074+
}
2075+
2076+
// **NOT** a safepoint
2077+
void *jl_gc_perm_alloc(size_t sz)
2078+
{
2079+
#ifndef MEMDEBUG
2080+
if (__unlikely(sz > GC_PERM_POOL_LIMIT))
2081+
#endif
2082+
return malloc(sz);
2083+
JL_LOCK_NOGC(&gc_perm_lock);
2084+
void *p = jl_gc_perm_alloc_nolock(sz);
2085+
JL_UNLOCK_NOGC(&gc_perm_lock);
2086+
return p;
2087+
}
2088+
20342089
JL_DLLEXPORT void jl_gc_add_finalizer(jl_value_t *v, jl_function_t *f)
20352090
{
20362091
jl_ptls_t ptls = jl_get_ptls_states();

src/jltypes.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,7 +3727,7 @@ void jl_init_types(void)
37273727
jl_emptysvec, jl_emptysvec, 0, 1, 0);
37283728
jl_array_typename = jl_array_type->name;
37293729
jl_array_type->ninitialized = 0;
3730-
static const struct _jl_datatype_layout_t _jl_array_layout = { 0, sizeof(void*), 0, 0, 0 };
3730+
static const jl_datatype_layout_t _jl_array_layout = { 0, sizeof(void*), 0, 0, 0 };
37313731
jl_array_type->layout = &_jl_array_layout;
37323732

37333733
jl_array_any_type =
@@ -3962,8 +3962,8 @@ void jl_init_types(void)
39623962
jl_compute_field_offsets(jl_sym_type);
39633963

39643964
// TODO: don't modify layout objects
3965-
((struct _jl_datatype_layout_t*)jl_sym_type->layout)->pointerfree = 0;
3966-
((struct _jl_datatype_layout_t*)jl_simplevector_type->layout)->pointerfree = 0;
3965+
((jl_datatype_layout_t*)jl_sym_type->layout)->pointerfree = 0;
3966+
((jl_datatype_layout_t*)jl_simplevector_type->layout)->pointerfree = 0;
39673967

39683968
empty_sym = jl_symbol("");
39693969
call_sym = jl_symbol("call");

src/julia.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ typedef struct {
328328
uint32_t offset; // offset relative to data start, excluding type tag
329329
} jl_fielddesc32_t;
330330

331-
struct _jl_datatype_layout_t {
331+
typedef struct {
332332
uint32_t nfields;
333333
uint32_t alignment : 28; // strictest alignment over all fields
334334
uint32_t haspadding : 1; // has internal undefined bytes
@@ -339,7 +339,7 @@ struct _jl_datatype_layout_t {
339339
// jl_fielddesc16_t field16[];
340340
// jl_fielddesc32_t field32[];
341341
// };
342-
};
342+
} jl_datatype_layout_t;
343343

344344
typedef struct _jl_datatype_t {
345345
JL_DATA_TYPE
@@ -348,7 +348,7 @@ typedef struct _jl_datatype_t {
348348
jl_svec_t *parameters;
349349
jl_svec_t *types;
350350
jl_value_t *instance; // for singletons
351-
const struct _jl_datatype_layout_t *layout;
351+
const jl_datatype_layout_t *layout;
352352
int32_t size; // TODO: move to _jl_datatype_layout_t
353353
int32_t ninitialized;
354354
uint32_t uid;
@@ -786,12 +786,12 @@ STATIC_INLINE char *jl_symbol_name_(jl_sym_t *s)
786786
}
787787
#define jl_symbol_name(s) jl_symbol_name_(s)
788788

789-
#define jl_dt_layout_fields(d) ((const char*)(d) + sizeof(struct _jl_datatype_layout_t))
789+
#define jl_dt_layout_fields(d) ((const char*)(d) + sizeof(jl_datatype_layout_t))
790790

791791
#define DEFINE_FIELD_ACCESSORS(f) \
792792
static inline uint32_t jl_field_##f(jl_datatype_t *st, int i) \
793793
{ \
794-
const struct _jl_datatype_layout_t *ly = st->layout; \
794+
const jl_datatype_layout_t *ly = st->layout; \
795795
assert(i >= 0 && (size_t)i < ly->nfields); \
796796
if (ly->fielddesc_type == 0) { \
797797
return ((const jl_fielddesc8_t*)jl_dt_layout_fields(ly))[i].f; \
@@ -808,7 +808,7 @@ DEFINE_FIELD_ACCESSORS(offset)
808808
DEFINE_FIELD_ACCESSORS(size)
809809
static inline int jl_field_isptr(jl_datatype_t *st, int i)
810810
{
811-
const struct _jl_datatype_layout_t *ly = st->layout;
811+
const jl_datatype_layout_t *ly = st->layout;
812812
assert(i >= 0 && (size_t)i < ly->nfields);
813813
return ((const jl_fielddesc8_t*)(jl_dt_layout_fields(ly) + (i << (ly->fielddesc_type + 1))))->isptr;
814814
}

src/julia_internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc(jl_ptls_t ptls, jl_gc_pool_t *p,
4444
int osize, int end_offset);
4545
JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t allocsz);
4646
int jl_gc_classify_pools(size_t sz, int *osize, int *end_offset);
47+
extern jl_mutex_t gc_perm_lock;
48+
void *jl_gc_perm_alloc_nolock(size_t sz);
49+
void *jl_gc_perm_alloc(size_t sz);
4750

4851
// pools are 16376 bytes large (GC_POOL_SZ - GC_PAGE_OFFSET)
4952
static const int jl_gc_sizeclasses[JL_GC_N_POOLS] = {

test/core.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,8 +3342,6 @@ typealias PossiblyInvalidUnion{T} Union{T,Int}
33423342
@test_throws TypeError PossiblyInvalidUnion{1}
33433343

33443344
# issue #12569
3345-
@test_throws ArgumentError Symbol("x"^10_000_000)
3346-
@test_throws ArgumentError gensym("x"^10_000_000)
33473345
@test Symbol("x") === Symbol("x")
33483346
@test split(string(gensym("abc")),'#')[3] == "abc"
33493347

0 commit comments

Comments
 (0)