Skip to content

Commit dd0a1c3

Browse files
authored
Support VO bit (#76)
This PR ports #59 to `dev`. In addition, this PR 1. introduces `jl_gc_permsymbol` for allocating the special perm object in `mk_symbol`, 2. removes some seemingly unnecessary post alloc calls for `jl_gc_perm_alloc` in `datatype.c`, and 3. does not support set VO bit using the slowpath (MMTk call).
1 parent 9f39431 commit dd0a1c3

File tree

6 files changed

+87
-22
lines changed

6 files changed

+87
-22
lines changed

src/gc-interface.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,14 @@ JL_DLLEXPORT void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align,
204204
// immortal region that is never swept. The second parameter specifies the type of the
205205
// object being allocated and will be used to set the object header.
206206
struct _jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT;
207-
207+
// permanently allocates a symbol (jl_sym_t). The object needs to be word aligned,
208+
// and tagged with jl_sym_tag.
209+
// FIXME: Ideally we should merge this with jl_gc_permobj, as symbol is an object.
210+
// Currently there are a few differences between the two functions, and refactoring is needed.
211+
// 1. sz for this function includes the object header, and sz for jl_gc_permobj excludes the header size.
212+
// 2. align for this function is word align, and align for jl_gc_permobj depends on the allocation size.
213+
// 3. ty for this function is jl_symbol_tag << 4, and ty for jl_gc_permobj is a datatype pointer.
214+
struct _jl_value_t *jl_gc_permsymbol(size_t sz) JL_NOTSAFEPOINT;
208215
// This function notifies the GC about memory addresses that are set when loading the boot image.
209216
// The GC may use that information to, for instance, determine that all objects in that chunk of memory should
210217
// be treated as marked and belonged to the old generation in nursery collections.

src/gc-mmtk.c

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -860,18 +860,28 @@ inline void* bump_alloc_fast(MMTkMutatorContext* mutator, uintptr_t* cursor, uin
860860
}
861861
}
862862

863+
inline void mmtk_set_side_metadata(const void* side_metadata_base, void* obj) {
864+
intptr_t addr = (intptr_t) obj;
865+
uint8_t* meta_addr = (uint8_t*) side_metadata_base + (addr >> 6);
866+
intptr_t shift = (addr >> 3) & 0b111;
867+
while(1) {
868+
uint8_t old_val = *meta_addr;
869+
uint8_t new_val = old_val | (1 << shift);
870+
if (jl_atomic_cmpswap((_Atomic(uint8_t)*)meta_addr, &old_val, new_val)) {
871+
break;
872+
}
873+
}
874+
}
875+
863876
inline void* mmtk_immix_alloc_fast(MMTkMutatorContext* mutator, size_t size, size_t align, size_t offset) {
864877
ImmixAllocator* allocator = &mutator->allocators.immix[MMTK_DEFAULT_IMMIX_ALLOCATOR];
865878
return bump_alloc_fast(mutator, (uintptr_t*)&allocator->cursor, (intptr_t)allocator->limit, size, align, offset, 0);
866879
}
867880

868-
inline void mmtk_immix_post_alloc_slow(MMTkMutatorContext* mutator, void* obj, size_t size) {
869-
mmtk_post_alloc(mutator, obj, size, 0);
870-
}
871-
872881
inline void mmtk_immix_post_alloc_fast(MMTkMutatorContext* mutator, void* obj, size_t size) {
873-
// FIXME: for now, we do nothing
874-
// but when supporting moving, this is where we set the valid object (VO) bit
882+
if (MMTK_NEEDS_VO_BIT) {
883+
mmtk_set_side_metadata(MMTK_SIDE_VO_BIT_BASE_ADDRESS, obj);
884+
}
875885
}
876886

877887
inline void* mmtk_immortal_alloc_fast(MMTkMutatorContext* mutator, size_t size, size_t align, size_t offset) {
@@ -881,16 +891,11 @@ inline void* mmtk_immortal_alloc_fast(MMTkMutatorContext* mutator, size_t size,
881891

882892
inline void mmtk_immortal_post_alloc_fast(MMTkMutatorContext* mutator, void* obj, size_t size) {
883893
if (MMTK_NEEDS_WRITE_BARRIER == MMTK_OBJECT_BARRIER) {
884-
intptr_t addr = (intptr_t) obj;
885-
uint8_t* meta_addr = (uint8_t*) (MMTK_SIDE_LOG_BIT_BASE_ADDRESS) + (addr >> 6);
886-
intptr_t shift = (addr >> 3) & 0b111;
887-
while(1) {
888-
uint8_t old_val = *meta_addr;
889-
uint8_t new_val = old_val | (1 << shift);
890-
if (jl_atomic_cmpswap((_Atomic(uint8_t)*)meta_addr, &old_val, new_val)) {
891-
break;
892-
}
893-
}
894+
mmtk_set_side_metadata(MMTK_SIDE_LOG_BIT_BASE_ADDRESS, obj);
895+
}
896+
897+
if (MMTK_NEEDS_VO_BIT) {
898+
mmtk_set_side_metadata(MMTK_SIDE_VO_BIT_BASE_ADDRESS, obj);
894899
}
895900
}
896901

@@ -1069,6 +1074,16 @@ jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT
10691074
return jl_valueof(o);
10701075
}
10711076

1077+
jl_value_t *jl_gc_permsymbol(size_t sz) JL_NOTSAFEPOINT
1078+
{
1079+
jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc(sz, 0, sizeof(void*), 0);
1080+
jl_value_t *sym = jl_valueof(tag);
1081+
jl_ptls_t ptls = jl_current_task->ptls;
1082+
jl_set_typetagof(sym, jl_symbol_tag, 0); // We need to set symbol tag. The GC tag doesnt matter.
1083+
mmtk_immortal_post_alloc_fast(&ptls->gc_tls.mmtk_mutator, sym, sz);
1084+
return sym;
1085+
}
1086+
10721087
JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz)
10731088
{
10741089
jl_ptls_t ptls = jl_current_task->ptls;

src/gc-stock.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3836,6 +3836,15 @@ jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT
38363836
return jl_valueof(o);
38373837
}
38383838

3839+
jl_value_t *jl_gc_permsymbol(size_t sz) JL_NOTSAFEPOINT
3840+
{
3841+
jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc(sz, 0, sizeof(void*), 0);
3842+
jl_value_t *sym = jl_valueof(tag);
3843+
// set to old marked so that we won't look at it in the GC or write barrier.
3844+
jl_set_typetagof(sym, jl_symbol_tag, GC_OLD_MARKED);
3845+
return sym;
3846+
}
3847+
38393848
JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void)
38403849
{
38413850
if (jl_is_initialized()) {

src/julia.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,7 +2748,13 @@ extern void mmtk_object_reference_write_slow(void* mutator, const void* parent,
27482748
#define MMTK_DEFAULT_IMMIX_ALLOCATOR (0)
27492749
#define MMTK_IMMORTAL_BUMP_ALLOCATOR (0)
27502750

2751+
// VO bit is required to support conservative stack scanning and moving.
2752+
#define MMTK_NEEDS_VO_BIT (1)
2753+
2754+
void mmtk_immortal_post_alloc_fast(MMTkMutatorContext* mutator, void* obj, size_t size);
2755+
27512756
extern const void* MMTK_SIDE_LOG_BIT_BASE_ADDRESS;
2757+
extern const void* MMTK_SIDE_VO_BIT_BASE_ADDRESS;
27522758

27532759
// Directly call into MMTk for write barrier (debugging only)
27542760
STATIC_INLINE void mmtk_gc_wb_full(const void *parent, const void *ptr) JL_NOTSAFEPOINT

src/llvm-late-gc-lowering-mmtk.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,37 @@ Value* LateLowerGCFrame::lowerGCAllocBytesLate(CallInst *target, Function &F)
132132

133133
auto v_raw = builder.CreateNSWAdd(result, ConstantInt::get(Type::getInt64Ty(target->getContext()), sizeof(jl_taggedvalue_t)));
134134
auto v_as_ptr = builder.CreateIntToPtr(v_raw, smallAllocFunc->getReturnType());
135+
136+
// Post alloc
137+
if (MMTK_NEEDS_VO_BIT) {
138+
auto intptr_ty = Type::getInt64Ty(target->getContext());
139+
auto i8_ty = Type::getInt8Ty(F.getContext());
140+
intptr_t metadata_base_address = reinterpret_cast<intptr_t>(MMTK_SIDE_VO_BIT_BASE_ADDRESS);
141+
auto metadata_base_val = ConstantInt::get(intptr_ty, metadata_base_address);
142+
auto metadata_base_ptr = ConstantExpr::getIntToPtr(metadata_base_val, PointerType::get(i8_ty, 0));
143+
144+
// intptr_t addr = (intptr_t) v;
145+
auto addr = v_raw;
146+
147+
// uint8_t* vo_meta_addr = (uint8_t*) (MMTK_SIDE_VO_BIT_BASE_ADDRESS) + (addr >> 6);
148+
auto shr = builder.CreateLShr(addr, ConstantInt::get(intptr_ty, 6));
149+
auto metadata_ptr = builder.CreateGEP(i8_ty, metadata_base_ptr, shr);
150+
151+
// intptr_t shift = (addr >> 3) & 0b111;
152+
auto shift = builder.CreateAnd(builder.CreateLShr(addr, ConstantInt::get(intptr_ty, 3)), ConstantInt::get(intptr_ty, 7));
153+
154+
// uint8_t byte_val = *vo_meta_addr;
155+
auto byte_val = builder.CreateAlignedLoad(i8_ty, metadata_ptr, Align());
156+
157+
// uint8_t new_val = byte_val | (1 << shift);
158+
auto shifted_val = builder.CreateShl(ConstantInt::get(intptr_ty, 1), shift);
159+
auto shifted_val_i8 = builder.CreateTruncOrBitCast(shifted_val, i8_ty);
160+
auto new_val = builder.CreateOr(byte_val, shifted_val_i8);
161+
162+
// (*vo_meta_addr) = new_val;
163+
builder.CreateStore(new_val, metadata_ptr);
164+
}
165+
135166
builder.CreateBr(next_instr->getParent());
136167

137168
phiNode->addIncoming(new_call, slowpath);

src/symbol.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "julia.h"
1111
#include "julia_internal.h"
1212
#include "julia_assert.h"
13+
#include "gc-interface.h"
1314

1415
#ifdef __cplusplus
1516
extern "C" {
@@ -34,12 +35,8 @@ static size_t symbol_nbytes(size_t len) JL_NOTSAFEPOINT
3435

3536
static jl_sym_t *mk_symbol(const char *str, size_t len) JL_NOTSAFEPOINT
3637
{
37-
jl_sym_t *sym;
3838
size_t nb = symbol_nbytes(len);
39-
jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc(nb, 0, sizeof(void*), 0);
40-
sym = (jl_sym_t*)jl_valueof(tag);
41-
// set to old marked so that we won't look at it in the GC or write barrier.
42-
jl_set_typetagof(sym, jl_symbol_tag, GC_OLD_MARKED);
39+
jl_sym_t *sym = (jl_sym_t*)jl_gc_permsymbol(nb);
4340
jl_atomic_store_relaxed(&sym->left, NULL);
4441
jl_atomic_store_relaxed(&sym->right, NULL);
4542
sym->hash = hash_symbol(str, len);

0 commit comments

Comments
 (0)