let join =
    let symetric_merge =
      M.symetric_merge
        ~cache:("map_Lattice",8192) ~decide_none ~decide_some
    in
    fun m1 m2 ->
      if m1 == m2 then m1 else
        let result =
          match m1, m2 with
          | Top(x1,a1), Top(x2,a2) ->
              Top(Top_Param.join x1 x2, Origin.join a1 a2)
          | Top (Top_Param.Top,_) as x, Map _
          | Map _, (Top (Top_Param.Top,_) as x) ->
              x
          | Top (Top_Param.Set t,a), Map m | Map m, Top (Top_Param.Set t,a) ->
              inject_top_origin a
                (M.fold
                   (fun k _ acc -> Top_Param.O.add k acc)
                   m
                   t)
          | Map mm1, Map mm2 ->
              let result = Map (symetric_merge mm1 mm2) in
              assert (

                  let n = succ !check_join_assert in
                  check_join_assert := n;
                  n land 63 <> 0  ||
                (let merge_key k v acc =
                  M.add k (V.join v (find_or_bottom k mm2)) acc
                in
                let r2 = Map (M.fold merge_key mm1 mm2) in
                if equal result r2 then
                  true
                else begin
                  Format.printf "Map_Lattice.join incorrect %a (%d;%x) %a (%d;%x) -> %a (%d;%x) %a (%d;%x)@."
                    pretty m1 (hash m1) (Extlib.address_of_value m1)
                    pretty m2 (hash m2) (Extlib.address_of_value m2)
                    pretty result (hash result) (Extlib.address_of_value result)
                    pretty r2 (hash r2) (Extlib.address_of_value r2);
                  false;
                  end));

              result
        in
        (*Format.printf "Map_Lattice_join@\nm1=%a@\nm2=%a@\nm1Um2=%a@\n"
          pretty m1 pretty m2 pretty result;*)

        result