Skip to content

Commit

Permalink
Make RTS data segment passive
Browse files Browse the repository at this point in the history
  • Loading branch information
luc-blaeser committed Feb 20, 2024
1 parent 76e6ff7 commit 716f872
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/linking/linkModule.ml
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,22 @@ let link (em1 : extended_module) libname (em2 : extended_module) =
add_or_get_ty fun_ty.it
in

(* Check that the first module generated by the compiler backend does not use
active data segments. *)
let is_active data_segment = match data_segment.it.dmode.it with
| Active _ -> true
| _ -> false
in
let em1_active_data_segments = List.filter is_active em1.module_.datas in
assert ((List.length em1_active_data_segments) = 0);

let is_passive data_segment = match data_segment.it.dmode.it with
| Passive -> true
| _ -> false
in
let em1_passive_data_segments = List.filter is_passive em1.module_.datas in
let dm2_data_segment_offset = List.length em1_passive_data_segments in

(* Rename types in first module *)
let em1_tys =
map_module (fun m -> { (rename_types (ty_renamer m.types) m) with types = [] }) em1
Expand Down Expand Up @@ -895,6 +911,63 @@ let link (em1 : extended_module) libname (em2 : extended_module) =
Int32.add (Int32.add lib_table_start dylink.table_size) (Int32.of_int (List.length got_func_imports))
in

(* Rust generates active data segments for the runtime system code that are not supported with orthogonal persistence.
Therefore, make the data segments passive and load them on initialization to their reserved static space.
Note: If Rust would also use passive data segments in future, the segment load indices need to be renumbered. *)
let make_rts_data_segments_passive : module_' -> module_' = fun m ->
let segment_mode' (dmode : segment_mode') =
match dmode with
| Active _ -> Passive
| _ -> raise (LinkError "Passive data segments are not yet supported in the RTS module")
in
let segment_mode = phrase (segment_mode') in
let data_segment' (s : data_segment') = { s with dmode = segment_mode s.dmode; } in
let data_segment = phrase (data_segment') in
let data_segments = List.map data_segment in
{ m with datas = data_segments m.datas; }
in

let load_rts_data_segments numbering_offset data_segments : module_' -> module_' = fun m ->
let imported_functions = Int32.to_int (count_imports is_fun_import m) in
let start_index = Int32.to_int (match m.start with
| Some index -> index.it
| None -> raise (LinkError "The module has no start function to inject"))
in
let local_start_function = Int.sub start_index imported_functions in
if local_start_function < 0 then
raise (LinkError "The module start refers to an imported function that cannot be injected");
assert (local_start_function < (List.length m.funcs));

let load_passive_segment index data_segment =
let segment_index = Int32.of_int (Int.add index numbering_offset) in
let compile_const_i32 value = Const (Wasm.Values.I32 value @@ no_region) @@ no_region in
let data_target = match data_segment.it.dmode.it with
| Active { offset; _ } -> offset.it
| _ -> raise (LinkError "Passive data segments are not yet supported in the RTS module")
in
let data_length = Int32.of_int (String.length data_segment.it.dinit) in
let memory_init = MemoryInit (segment_index @@ no_region) @@ no_region in
data_target @
[
compile_const_i32 0l; (* data offset *)
compile_const_i32 data_length;
memory_init
]
in
let load_passive_segments = List.concat (List.mapi load_passive_segment data_segments) in

let inject_in_func' code f = { f with body = code @ f.body } in
let inject_in_func code = phrase (inject_in_func' code) in
let patch_functions functions =
List.mapi (fun index func ->
if index = local_start_function then
inject_in_func load_passive_segments func
else func
) functions
in
{ m with funcs = patch_functions m.funcs; }
in

let merged = join_modules
( em1_tys
|> map_module (fun m -> { m with types = type_indices_sorted })
Expand All @@ -908,6 +981,7 @@ let link (em1 : extended_module) libname (em2 : extended_module) =
|> map_module (set_table_size new_table_size)
)
( dm2
|> make_rts_data_segments_passive
|> remove_imports is_fun_import fun_resolved21
|> remove_imports is_global_import global_resolved21
|> remove_imports is_memory_import [0l, 0l]
Expand All @@ -923,6 +997,7 @@ let link (em1 : extended_module) libname (em2 : extended_module) =
type_indices
|> add_call_ctors
|> remove_non_ic_exports (* only sane if no additional files get linked in *)
|> map_module (load_rts_data_segments dm2_data_segment_offset dm2.datas)
in

(* Rename global and function indices in GOT.func stuff *)
Expand Down

0 comments on commit 716f872

Please sign in to comment.