Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memoise last substitution composition #1209

Merged
merged 1 commit into from
Mar 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Memoise last substitution composition
This adds memoisation for the last `compose` operation to `Subst`. It
seems that we often unfold a lazy signature by one level and then
substitute into it. In such a case, we will repeatedly compose the same
two substitutions for each lazy child of the signature. By memoising
this last composition, we avoid this extra work which seems to be worth
about 1% in both time and allocations currently. This will become much
more important when we introduce lazy value_descriptions.

It doesn't seem to matter much which of the two substitutions we memoise
on. I also tried just memoising one composition globally and that seemed
to be slightly worse.
  • Loading branch information
Roman Leshchinskiy committed Mar 14, 2023
commit 17b49ea26cf8b150f76266a4b6c7d3acc3ded9a0
39 changes: 26 additions & 13 deletions ocaml/typing/subst.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,37 @@ type t =
modtypes: module_type Path.Map.t;
for_saving: bool;
loc: Location.t option;
mutable last_compose: (t * t) option (* Memoized composition *)
}

let identity =
{ types = Path.Map.empty;
modules = Path.Map.empty;
modtypes = Path.Map.empty;
for_saving = false;
loc = None;
last_compose = None;
}

let add_type_path id p s = { s with types = Path.Map.add id (Path p) s.types }
let add_type_path id p s =
{ s with types = Path.Map.add id (Path p) s.types; last_compose = None }
let add_type id p s = add_type_path (Pident id) p s

let add_type_function id ~params ~body s =
{ s with types = Path.Map.add id (Type_function { params; body }) s.types }
{ s with types = Path.Map.add id (Type_function { params; body }) s.types;
last_compose = None
}

let add_module_path id p s = { s with modules = Path.Map.add id p s.modules }
let add_module_path id p s =
{ s with modules = Path.Map.add id p s.modules; last_compose = None }
let add_module id p s = add_module_path (Pident id) p s

let add_modtype_path p ty s = { s with modtypes = Path.Map.add p ty s.modtypes }
let add_modtype_path p ty s =
{ s with modtypes = Path.Map.add p ty s.modtypes; last_compose = None }
let add_modtype id ty s = add_modtype_path (Pident id) ty s

let for_saving s = { s with for_saving = true }
let for_saving s = { s with for_saving = true; last_compose = None }

let change_locs s loc = { s with loc = Some loc }
let change_locs s loc = { s with loc = Some loc; last_compose = None }

let loc s x =
match s.loc with
Expand Down Expand Up @@ -717,12 +723,19 @@ and modtype scoping s t =
and compose s1 s2 =
if s1 == identity then s2 else
if s2 == identity then s1 else
{ types = merge_path_maps (type_replacement s2) s1.types s2.types;
modules = merge_path_maps (module_path s2) s1.modules s2.modules;
modtypes = merge_path_maps (modtype Keep s2) s1.modtypes s2.modtypes;
for_saving = s1.for_saving || s2.for_saving;
loc = keep_latest_loc s1.loc s2.loc;
}
match s2.last_compose with
| Some (t,s) when t == s1 -> s
| _ ->
let s =
{ types = merge_path_maps (type_replacement s2) s1.types s2.types;
modules = merge_path_maps (module_path s2) s1.modules s2.modules;
modtypes = merge_path_maps (modtype Keep s2) s1.modtypes s2.modtypes;
for_saving = s1.for_saving || s2.for_saving;
loc = keep_latest_loc s1.loc s2.loc;
last_compose = None
}
in
s2.last_compose <- Some (s1,s); s


let subst_lazy_signature_item scoping s comp =
Expand Down