Skip to content

Commit 841ebc6

Browse files
committed
make objectid effects total
Avoids the need to rehash most dictionaries on reload. System image data size increase is about 109MB -> 112MB, since there are about 130k Arrays, 75k CodeInstances, 30k Methods, 80k TypeMapEntries, 75k MethodInstance, and 36k Core.Bindings, and other mutable objects.
1 parent 8944a22 commit 841ebc6

8 files changed

+63
-58
lines changed

base/reflection.jl

+3-11
Original file line numberDiff line numberDiff line change
@@ -720,18 +720,10 @@ If `x === y` then `objectid(x) == objectid(y)`, and usually when `x !== y`, `obj
720720
721721
See also [`hash`](@ref), [`IdDict`](@ref).
722722
"""
723-
function objectid(x)
724-
# objectid is foldable iff it isn't a pointer.
725-
if isidentityfree(typeof(x))
726-
return _foldable_objectid(x)
727-
end
728-
return _objectid(x)
729-
end
730-
function _foldable_objectid(@nospecialize(x))
731-
@_foldable_meta
732-
_objectid(x)
723+
function objectid(@nospecialize(x))
724+
@_total_meta
725+
return ccall(:jl_object_id, UInt, (Any,), x)
733726
end
734-
_objectid(@nospecialize(x)) = ccall(:jl_object_id, UInt, (Any,), x)
735727

736728
"""
737729
isdispatchtuple(T)

src/builtins.c

+34-25
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN
344344
i++;
345345
pe = pe->prev;
346346
}
347+
uintptr_t bits = jl_astaggedvalue(v)->header;
348+
if (bits & GC_IN_IMAGE)
349+
return ((uintptr_t*)v)[-2];
347350
return inthash((uintptr_t)v);
348351
}
349352
if (tv == jl_uniontype_type) {
@@ -432,50 +435,56 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT
432435
return h;
433436
}
434437

435-
static uintptr_t NOINLINE jl_object_id__cold(jl_datatype_t *dt, jl_value_t *v) JL_NOTSAFEPOINT
438+
static uintptr_t NOINLINE jl_object_id__cold(uintptr_t tv, jl_value_t *v) JL_NOTSAFEPOINT
436439
{
437-
if (dt == jl_simplevector_type)
438-
return hash_svec((jl_svec_t*)v);
439-
if (dt == jl_datatype_type) {
440-
jl_datatype_t *dtv = (jl_datatype_t*)v;
441-
uintptr_t h = ~dtv->name->hash;
442-
return bitmix(h, hash_svec(dtv->parameters));
443-
}
444-
if (dt == jl_string_type) {
440+
jl_datatype_t *dt = (jl_datatype_t*)jl_to_typeof(tv);
441+
if (dt->name->mutabl) {
442+
if (dt == jl_string_type) {
445443
#ifdef _P64
446-
return memhash_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677);
444+
return memhash_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677);
447445
#else
448-
return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677);
446+
return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677);
449447
#endif
450-
}
451-
if (dt == jl_module_type) {
452-
jl_module_t *m = (jl_module_t*)v;
453-
return m->hash;
454-
}
455-
if (dt->name->mutabl)
448+
}
449+
if (dt == jl_simplevector_type)
450+
return hash_svec((jl_svec_t*)v);
451+
if (dt == jl_datatype_type) {
452+
jl_datatype_t *dtv = (jl_datatype_t*)v;
453+
uintptr_t h = ~dtv->name->hash;
454+
return bitmix(h, hash_svec(dtv->parameters));
455+
}
456+
if (dt == jl_module_type) {
457+
jl_module_t *m = (jl_module_t*)v;
458+
return m->hash;
459+
}
460+
uintptr_t bits = jl_astaggedvalue(v)->header;
461+
if (bits & GC_IN_IMAGE)
462+
return ((uintptr_t*)v)[-2];
456463
return inthash((uintptr_t)v);
464+
}
457465
return immut_id_(dt, v, dt->hash);
458466
}
459467

460-
JL_DLLEXPORT inline uintptr_t jl_object_id_(jl_value_t *tv, jl_value_t *v) JL_NOTSAFEPOINT
468+
JL_DLLEXPORT inline uintptr_t jl_object_id_(uintptr_t tv, jl_value_t *v) JL_NOTSAFEPOINT
461469
{
462-
jl_datatype_t *dt = (jl_datatype_t*)tv;
463-
if (dt == jl_symbol_type)
470+
if (tv == jl_symbol_tag << 4) {
464471
return ((jl_sym_t*)v)->hash;
465-
if (dt == jl_typename_type)
466-
return ((jl_typename_t*)v)->hash;
467-
if (dt == jl_datatype_type) {
472+
}
473+
else if (tv == jl_datatype_tag << 4) {
468474
jl_datatype_t *dtv = (jl_datatype_t*)v;
469475
if (dtv->isconcretetype)
470476
return dtv->hash;
471477
}
472-
return jl_object_id__cold(dt, v);
478+
else if (tv == (uintptr_t)jl_typename_type) {
479+
return ((jl_typename_t*)v)->hash;
480+
}
481+
return jl_object_id__cold(tv, v);
473482
}
474483

475484

476485
JL_DLLEXPORT uintptr_t jl_object_id(jl_value_t *v) JL_NOTSAFEPOINT
477486
{
478-
return jl_object_id_(jl_typeof(v), v);
487+
return jl_object_id_(jl_typetagof(v), v);
479488
}
480489

481490
// eq hash table --------------------------------------------------------------

src/ccall.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
18801880
if (!val.isghost && !val.ispointer())
18811881
val = value_to_pointer(ctx, val);
18821882
Value *args[] = {
1883-
emit_typeof(ctx, val),
1883+
emit_typeof(ctx, val, false, true),
18841884
val.isghost ? ConstantPointerNull::get(T_pint8_derived) :
18851885
ctx.builder.CreateBitCast(
18861886
decay_derived(ctx, data_pointer(ctx, val)),

src/codegen.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ static const auto jlapplytype_func = new JuliaFunction<>{
11651165
static const auto jl_object_id__func = new JuliaFunction<TypeFnContextAndSizeT>{
11661166
XSTR(jl_object_id_),
11671167
[](LLVMContext &C, Type *T_size) { return FunctionType::get(T_size,
1168-
{JuliaType::get_prjlvalue_ty(C), PointerType::get(getInt8Ty(C), AddressSpace::Derived)}, false); },
1168+
{T_size, PointerType::get(getInt8Ty(C), AddressSpace::Derived)}, false); },
11691169
nullptr,
11701170
};
11711171
static const auto setjmp_func = new JuliaFunction<TypeFnContextAndTriple>{

src/iddict.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// compute empirical max-probe for a given size
66
#define max_probe(size) ((size) <= 1024 ? 16 : (size) >> 6)
77

8-
#define keyhash(k) jl_object_id_(jl_typeof(k), k)
8+
#define keyhash(k) jl_object_id_(jl_typetagof(k), k)
99
#define h2index(hv, sz) (size_t)(((hv) & ((sz)-1)) * 2)
1010

1111
static inline int jl_table_assign_bp(jl_genericmemory_t **pa, jl_value_t *key, jl_value_t *val);

src/julia_internal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,7 @@ JL_DLLEXPORT int jl_stored_inline(jl_value_t *el_type);
13701370
JL_DLLEXPORT jl_value_t *(jl_array_data_owner)(jl_array_t *a);
13711371
JL_DLLEXPORT jl_array_t *jl_array_copy(jl_array_t *ary);
13721372

1373-
JL_DLLEXPORT uintptr_t jl_object_id_(jl_value_t *tv, jl_value_t *v) JL_NOTSAFEPOINT;
1373+
JL_DLLEXPORT uintptr_t jl_object_id_(uintptr_t tv, jl_value_t *v) JL_NOTSAFEPOINT;
13741374
JL_DLLEXPORT void jl_set_next_task(jl_task_t *task) JL_NOTSAFEPOINT;
13751375

13761376
// -- synchronization utilities -- //

src/staticdata.c

+15-18
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,6 @@ typedef struct {
500500
int8_t incremental;
501501
} jl_serializer_state;
502502

503-
static jl_value_t *jl_idtable_type = NULL;
504-
static jl_typename_t *jl_idtable_typename = NULL;
505503
static jl_value_t *jl_bigint_type = NULL;
506504
static int gmp_limb_size = 0;
507505
static jl_sym_t *jl_docmeta_sym = NULL;
@@ -1252,24 +1250,35 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
12521250
assert(!(s->incremental && jl_object_in_image(v)));
12531251
jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v);
12541252
assert((!jl_is_datatype_singleton(t) || t->instance == v) && "detected singleton construction corruption");
1253+
int mutabl = t->name->mutabl;
12551254
ios_t *f = s->s;
12561255
if (t->smalltag) {
12571256
if (t->layout->npointers == 0 || t == jl_string_type) {
1258-
if (jl_datatype_nfields(t) == 0 || t->name->mutabl == 0 || t == jl_string_type) {
1257+
if (jl_datatype_nfields(t) == 0 || mutabl == 0 || t == jl_string_type) {
12591258
f = s->const_data;
12601259
}
12611260
}
12621261
}
12631262

1264-
// realign stream to expected gc alignment (16 bytes)
1263+
// realign stream to expected gc alignment (16 bytes) after tag
12651264
uintptr_t skip_header_pos = ios_pos(f) + sizeof(jl_taggedvalue_t);
1265+
uintptr_t object_id_expected = mutabl &&
1266+
t != jl_datatype_type &&
1267+
t != jl_typename_type &&
1268+
t != jl_string_type &&
1269+
t != jl_simplevector_type &&
1270+
t != jl_module_type;
1271+
if (object_id_expected)
1272+
skip_header_pos += sizeof(size_t);
12661273
write_padding(f, LLT_ALIGN(skip_header_pos, 16) - skip_header_pos);
12671274

12681275
// write header
1276+
if (object_id_expected)
1277+
write_uint(f, jl_object_id(v));
12691278
if (s->incremental && jl_needs_serialization(s, (jl_value_t*)t) && needs_uniquing((jl_value_t*)t))
12701279
arraylist_push(&s->uniquing_types, (void*)(uintptr_t)(ios_pos(f)|1));
12711280
if (f == s->const_data)
1272-
write_uint(s->const_data, ((uintptr_t)t->smalltag << 4) | GC_OLD_MARKED);
1281+
write_uint(s->const_data, ((uintptr_t)t->smalltag << 4) | GC_OLD_MARKED | GC_IN_IMAGE);
12731282
else
12741283
write_gctaggedfield(s, t);
12751284
size_t reloc_offset = ios_pos(f);
@@ -1717,11 +1726,6 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
17171726
arraylist_push(&s->fixup_objs, (void*)reloc_offset);
17181727
}
17191728
}
1720-
else if (((jl_datatype_t*)(jl_typeof(v)))->name == jl_idtable_typename) {
1721-
assert(f == s->s);
1722-
// will need to rehash this, later (after types are fully constructed)
1723-
arraylist_push(&s->fixup_objs, (void*)reloc_offset);
1724-
}
17251729
else if (jl_is_genericmemoryref(v)) {
17261730
assert(f == s->s);
17271731
record_memoryref(s, reloc_offset, *(jl_genericmemoryref_t*)v);
@@ -2581,8 +2585,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
25812585
}
25822586
}
25832587
}
2584-
jl_idtable_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("IdDict")) : NULL;
2585-
jl_idtable_typename = jl_base_module ? ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_idtable_type))->name : NULL;
25862588
jl_bigint_type = jl_base_module ? jl_get_global(jl_base_module, jl_symbol("BigInt")) : NULL;
25872589
if (jl_bigint_type) {
25882590
gmp_limb_size = jl_unbox_long(jl_get_global((jl_module_t*)jl_get_global(jl_base_module, jl_symbol("GMP")),
@@ -3408,12 +3410,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
34083410
}
34093411
}
34103412
else {
3411-
// rehash IdDict
3412-
//assert(((jl_datatype_t*)(jl_typeof(obj)))->name == jl_idtable_typename);
3413-
jl_genericmemory_t **a = (jl_genericmemory_t**)obj;
3414-
assert(jl_typetagis(*a, jl_memory_any_type));
3415-
*a = jl_idtable_rehash(*a, (*a)->length);
3416-
jl_gc_wb(obj, *a);
3413+
abort();
34173414
}
34183415
}
34193416
// Now pick up the globalref binding pointer field

test/precompile.jl

+7
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ precompile_test_harness(false) do dir
288288
a_vec_inline = Pair{Int,Any}[]
289289
push!(a_vec_inline, 1=>2, 3=>4)
290290
a_mat_inline = reshape(a_vec_inline, (1, 2))
291+
292+
oid_vec_int = objectid(a_vec_int)
293+
oid_mat_int = objectid(a_mat_int)
291294
end
292295
""")
293296
# Issue #12623
@@ -371,6 +374,10 @@ precompile_test_harness(false) do dir
371374
@test Foo.a_mat_inline == Pair{Int,Any}[1=>2 3=>4]
372375
Foo.a_mat_inline[1, 2] = 5=>6
373376
@test Foo.a_vec_inline[2] === Pair{Int,Any}(5, 6)
377+
378+
@test objectid(Foo.a_vec_int) === Foo.oid_vec_int
379+
@test objectid(Foo.a_mat_int) === Foo.oid_mat_int
380+
@test Foo.oid_vec_int !== Foo.oid_mat_int
374381
end
375382

376383
@eval begin function ccallable_test()

0 commit comments

Comments
 (0)