@@ -491,6 +491,7 @@ void *native_functions; // opaque jl_native_code_desc_t blob used for fetching
491491
492492// table of struct field addresses to rewrite during saving
493493static htable_t field_replace ;
494+ static htable_t bits_replace ;
494495static htable_t relocatable_ext_cis ;
495496
496497// array of definitions for the predefined function pointers
@@ -1605,7 +1606,23 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
16051606 write_padding (f , offset - tot );
16061607 tot = offset ;
16071608 size_t fsz = jl_field_size (t , i );
1608- if (t -> name -> mutabl && jl_is_cpointer_type (jl_field_type_concrete (t , i )) && * (intptr_t * )slot != -1 ) {
1609+ jl_value_t * replace = (jl_value_t * )ptrhash_get (& bits_replace , (void * )slot );
1610+ if (replace != HT_NOTFOUND ) {
1611+ assert (t -> name -> mutabl && !jl_field_isptr (t , i ));
1612+ jl_value_t * rty = jl_typeof (replace );
1613+ size_t sz = jl_datatype_size (rty );
1614+ ios_write (f , (const char * )replace , sz );
1615+ jl_value_t * ft = jl_field_type_concrete (t , i );
1616+ int isunion = jl_is_uniontype (ft );
1617+ unsigned nth = 0 ;
1618+ if (!jl_find_union_component (ft , rty , & nth ))
1619+ assert (0 && "invalid field assignment to isbits union" );
1620+ assert (sz <= fsz - isunion );
1621+ write_padding (f , fsz - sz - isunion );
1622+ if (isunion )
1623+ write_uint8 (f , nth );
1624+ }
1625+ else if (t -> name -> mutabl && jl_is_cpointer_type (jl_field_type_concrete (t , i )) && * (intptr_t * )slot != -1 ) {
16091626 // reset Ptr fields to C_NULL (but keep MAP_FAILED / INVALID_HANDLE)
16101627 assert (!jl_field_isptr (t , i ));
16111628 write_pointer (f );
@@ -2552,6 +2569,65 @@ jl_mutex_t global_roots_lock;
25522569extern jl_mutex_t world_counter_lock ;
25532570extern size_t jl_require_world ;
25542571
2572+ jl_mutex_t precompile_field_replace_lock ;
2573+ jl_svec_t * precompile_field_replace JL_GLOBALLY_ROOTED ;
2574+
2575+ static inline jl_value_t * get_checked_fieldindex (const char * name , jl_datatype_t * st , jl_value_t * v , jl_value_t * arg , int mutabl )
2576+ {
2577+ if (mutabl ) {
2578+ if (st == jl_module_type )
2579+ jl_error ("cannot assign variables in other modules" );
2580+ if (!st -> name -> mutabl )
2581+ jl_errorf ("%s: immutable struct of type %s cannot be changed" , name , jl_symbol_name (st -> name -> name ));
2582+ }
2583+ size_t idx ;
2584+ if (jl_is_long (arg )) {
2585+ idx = jl_unbox_long (arg ) - 1 ;
2586+ if (idx >= jl_datatype_nfields (st ))
2587+ jl_bounds_error (v , arg );
2588+ }
2589+ else if (jl_is_symbol (arg )) {
2590+ idx = jl_field_index (st , (jl_sym_t * )arg , 1 );
2591+ arg = jl_box_long (idx );
2592+ }
2593+ else {
2594+ jl_value_t * ts [2 ] = {(jl_value_t * )jl_long_type , (jl_value_t * )jl_symbol_type };
2595+ jl_value_t * t = jl_type_union (ts , 2 );
2596+ jl_type_error (name , t , arg );
2597+ }
2598+ if (mutabl && jl_field_isconst (st , idx )) {
2599+ jl_errorf ("%s: const field .%s of type %s cannot be changed" , name ,
2600+ jl_symbol_name ((jl_sym_t * )jl_svecref (jl_field_names (st ), idx )), jl_symbol_name (st -> name -> name ));
2601+ }
2602+ return arg ;
2603+ }
2604+
2605+ JL_DLLEXPORT void jl_set_precompile_field_replace (jl_value_t * val , jl_value_t * field , jl_value_t * newval )
2606+ {
2607+ if (!jl_generating_output ())
2608+ return ;
2609+ jl_datatype_t * st = (jl_datatype_t * )jl_typeof (val );
2610+ jl_value_t * idx = get_checked_fieldindex ("setfield!" , st , val , field , 1 );
2611+ JL_GC_PUSH1 (& idx );
2612+ size_t idxval = jl_unbox_long (idx );
2613+ jl_value_t * ft = jl_field_type_concrete (st , idxval );
2614+ if (!jl_isa (newval , ft ))
2615+ jl_type_error ("setfield!" , ft , newval );
2616+ JL_LOCK (& precompile_field_replace_lock );
2617+ if (precompile_field_replace == NULL ) {
2618+ precompile_field_replace = jl_alloc_svec (3 );
2619+ jl_svecset (precompile_field_replace , 0 , jl_alloc_vec_any (0 ));
2620+ jl_svecset (precompile_field_replace , 1 , jl_alloc_vec_any (0 ));
2621+ jl_svecset (precompile_field_replace , 2 , jl_alloc_vec_any (0 ));
2622+ }
2623+ jl_array_ptr_1d_push ((jl_array_t * )jl_svecref (precompile_field_replace , 0 ), val );
2624+ jl_array_ptr_1d_push ((jl_array_t * )jl_svecref (precompile_field_replace , 1 ), idx );
2625+ jl_array_ptr_1d_push ((jl_array_t * )jl_svecref (precompile_field_replace , 2 ), newval );
2626+ JL_GC_POP ();
2627+ JL_UNLOCK (& precompile_field_replace_lock );
2628+ }
2629+
2630+
25552631JL_DLLEXPORT int jl_is_globally_rooted (jl_value_t * val JL_MAYBE_UNROOTED ) JL_NOTSAFEPOINT
25562632{
25572633 if (jl_is_datatype (val )) {
@@ -2671,9 +2747,41 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
26712747 jl_array_t * ext_targets , jl_array_t * edges ) JL_GC_DISABLED
26722748{
26732749 htable_new (& field_replace , 0 );
2750+ htable_new (& bits_replace , 0 );
26742751 // strip metadata and IR when requested
26752752 if (jl_options .strip_metadata || jl_options .strip_ir )
26762753 jl_strip_all_codeinfos ();
2754+ // prepare hash table with any fields the user wanted us to rewrite during serialization
2755+ if (precompile_field_replace ) {
2756+ jl_array_t * vals = (jl_array_t * )jl_svecref (precompile_field_replace , 0 );
2757+ jl_array_t * fields = (jl_array_t * )jl_svecref (precompile_field_replace , 1 );
2758+ jl_array_t * newvals = (jl_array_t * )jl_svecref (precompile_field_replace , 2 );
2759+ size_t i , l = jl_array_nrows (vals );
2760+ assert (jl_array_nrows (fields ) == l && jl_array_nrows (newvals ) == l );
2761+ for (i = 0 ; i < l ; i ++ ) {
2762+ jl_value_t * val = jl_array_ptr_ref (vals , i );
2763+ size_t field = jl_unbox_long (jl_array_ptr_ref (fields , i ));
2764+ jl_value_t * newval = jl_array_ptr_ref (newvals , i );
2765+ jl_datatype_t * st = (jl_datatype_t * )jl_typeof (val );
2766+ size_t offs = jl_field_offset (st , field );
2767+ char * fldaddr = (char * )val + offs ;
2768+ if (jl_field_isptr (st , field )) {
2769+ record_field_change ((jl_value_t * * )fldaddr , newval );
2770+ }
2771+ else {
2772+ // replace the bits
2773+ ptrhash_put (& bits_replace , (void * )fldaddr , newval );
2774+ // and any pointers inside
2775+ jl_datatype_t * rty = (jl_datatype_t * )jl_typeof (newval );
2776+ const jl_datatype_layout_t * layout = rty -> layout ;
2777+ size_t j , np = layout -> npointers ;
2778+ for (j = 0 ; j < np ; j ++ ) {
2779+ uint32_t ptr = jl_ptr_offset (rty , j );
2780+ record_field_change ((jl_value_t * * )fldaddr + ptr , * (((jl_value_t * * )newval ) + ptr ));
2781+ }
2782+ }
2783+ }
2784+ }
26772785
26782786 int en = jl_gc_enable (0 );
26792787 nsym_tag = 0 ;
@@ -2966,6 +3074,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
29663074 arraylist_free (& gvars );
29673075 arraylist_free (& external_fns );
29683076 htable_free (& field_replace );
3077+ htable_free (& bits_replace );
29693078 htable_free (& serialization_order );
29703079 htable_free (& nullptrs );
29713080 htable_free (& symbol_table );
0 commit comments