Add VmModule.mmap() to Python API. (#14124)

We really need page aligned flatbuffer blobs vs normal malloc alignment.
The best way to be loading a file is via mmap, so just make that
available as an API.

This could be done in Python by the caller but is error-prone. The
public API will make this more robust.

Provides the mechanism to fix #13887
diff --git a/runtime/bindings/python/vm.cc b/runtime/bindings/python/vm.cc
index b72ecde..9a3a4fd 100644
--- a/runtime/bindings/python/vm.cc
+++ b/runtime/bindings/python/vm.cc
@@ -150,6 +150,23 @@
   return py_module;
 }
 
+VmModule VmModule::MMap(VmInstance* instance, std::string filepath) {
+  IREE_TRACE_SCOPE_NAMED("VmModule::MMap");
+  auto mmap_module = py::module::import("mmap");
+  auto open_func = py::module::import("io").attr("open");
+  auto file_obj = open_func(filepath, "r+b");
+  auto flags = py::cast<int64_t>(mmap_module.attr("MAP_SHARED"));
+  // MAP_POPULATE isn't available on all versions/platforms.
+  if (py::hasattr(mmap_module, "MAP_POPULATE")) {
+    flags |= py::cast<int64_t>(mmap_module.attr("MAP_POPULATE"));
+  }
+  auto prot = py::cast<int64_t>(mmap_module.attr("PROT_READ"));
+  auto mapped_file =
+      mmap_module.attr("mmap")(file_obj.attr("fileno")(), 0, flags, prot);
+  mapped_file.attr("madvise")(mmap_module.attr("MADV_RANDOM"));
+  return FromFlatbufferBlob(instance, mapped_file);
+}
+
 VmModule VmModule::FromFlatbufferBlob(VmInstance* instance,
                                       py::object flatbuffer_blob_object) {
   IREE_TRACE_SCOPE_NAMED("VmModule::FromFlatbufferBlob");
@@ -661,6 +678,7 @@
       .def_static("resolve_module_dependency",
                   &VmModule::ResolveModuleDependency)
       .def_static("from_flatbuffer", &VmModule::FromFlatbufferBlob)
+      .def_static("mmap", &VmModule::MMap)
       .def_property_readonly("name", &VmModule::name)
       .def_property_readonly("version",
                              [](VmModule& self) {