Add low_4gb MemMap and remove ashmem support for Fuchsia

Test: Tested with Fuchsia build system go/fuchsia-android
Change-Id: I61b09614d6f4d24bf9c975baa1f34c6b5735ca3d
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index adf0ad6..4ee48da 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -31,6 +31,8 @@
         "base/malloc_arena_pool.cc",
         "base/memory_region.cc",
         "base/mem_map.cc",
+        // "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong
+        "base/mem_map_unix.cc",
         "base/os_linux.cc",
         "base/runtime_debug.cc",
         "base/safe_copy.cc",
diff --git a/libartbase/base/fuchsia_compat.h b/libartbase/base/fuchsia_compat.h
new file mode 100644
index 0000000..018bac0
--- /dev/null
+++ b/libartbase/base/fuchsia_compat.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_
+#define ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_
+
+// stubs for features lacking in Fuchsia
+
+struct rlimit {
+  int rlim_cur;
+};
+
+#define RLIMIT_FSIZE (1)
+#define RLIM_INFINITY (-1)
+static int getrlimit(int resource, struct rlimit *rlim) {
+  LOG(FATAL) << "getrlimit not available for Fuchsia";
+}
+
+static int ashmem_create_region(const char *name, size_t size) {
+  LOG(FATAL) << "ashmem_create_region not available for Fuchsia";
+}
+
+#endif  // ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_
diff --git a/libartbase/base/globals.h b/libartbase/base/globals.h
index 39e0c50..cd0bf8f 100644
--- a/libartbase/base/globals.h
+++ b/libartbase/base/globals.h
@@ -74,7 +74,9 @@
 // ART_TARGET - Defined for target builds of ART.
 // ART_TARGET_LINUX - Defined for target Linux builds of ART.
 // ART_TARGET_ANDROID - Defined for target Android builds of ART.
-// Note: Either ART_TARGET_LINUX or ART_TARGET_ANDROID need to be set when ART_TARGET is set.
+// ART_TARGET_FUCHSIA - Defined for Fuchsia builds of ART.
+// Note: Either ART_TARGET_LINUX, ART_TARGET_ANDROID or ART_TARGET_FUCHSIA
+//       need to be set when ART_TARGET is set.
 // Note: When ART_TARGET_LINUX is defined mem_map.h will not be using Ashmem for memory mappings
 // (usually only available on Android kernels).
 #if defined(ART_TARGET)
@@ -82,10 +84,16 @@
 static constexpr bool kIsTargetBuild = true;
 # if defined(ART_TARGET_LINUX)
 static constexpr bool kIsTargetLinux = true;
+static constexpr bool kIsTargetFuchsia = false;
 # elif defined(ART_TARGET_ANDROID)
 static constexpr bool kIsTargetLinux = false;
+static constexpr bool kIsTargetFuchsia = false;
+# elif defined(ART_TARGET_FUCHSIA)
+static constexpr bool kIsTargetLinux = false;
+static constexpr bool kIsTargetFuchsia = true;
 # else
-# error "Either ART_TARGET_LINUX or ART_TARGET_ANDROID needs to be defined for target builds."
+# error "Either ART_TARGET_LINUX, ART_TARGET_ANDROID or ART_TARGET_FUCHSIA " \
+        "needs to be defined for target builds."
 # endif
 #else
 static constexpr bool kIsTargetBuild = false;
@@ -93,8 +101,11 @@
 # error "ART_TARGET_LINUX defined for host build."
 # elif defined(ART_TARGET_ANDROID)
 # error "ART_TARGET_ANDROID defined for host build."
+# elif defined(ART_TARGET_FUCHSIA)
+# error "ART_TARGET_FUCHSIA defined for host build."
 # else
 static constexpr bool kIsTargetLinux = false;
+static constexpr bool kIsTargetFuchsia = false;
 # endif
 #endif
 
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index c455fed..3ce2b51 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -19,7 +19,7 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
-#ifndef ANDROID_OS
+#if !defined(ANDROID_OS) && !defined(__Fuchsia__)
 #include <sys/resource.h>
 #endif
 
@@ -29,7 +29,12 @@
 
 #include "android-base/stringprintf.h"
 #include "android-base/unique_fd.h"
+
+#if !defined(__Fuchsia__)
 #include "cutils/ashmem.h"
+#else
+#include "fuchsia_compat.h"
+#endif
 
 #include "allocator.h"
 #include "bit_utils.h"
@@ -161,7 +166,7 @@
 // non-null, we check that pointer is the actual_ptr == expected_ptr,
 // and if not, report in error_msg what the conflict mapping was if
 // found, or a generic error in other cases.
-static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte_count,
+bool MemMap::CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte_count,
                             std::string* error_msg) {
   // Handled first by caller for more specific error messages.
   CHECK(actual_ptr != MAP_FAILED);
@@ -178,7 +183,7 @@
   }
 
   // We asked for an address but didn't get what we wanted, all paths below here should fail.
-  int result = munmap(actual_ptr, byte_count);
+  int result = TargetMUnmap(actual_ptr, byte_count);
   if (result == -1) {
     PLOG(WARNING) << StringPrintf("munmap(%p, %zd) failed", actual_ptr, byte_count);
   }
@@ -207,18 +212,18 @@
 }
 
 #if USE_ART_LOW_4G_ALLOCATOR
-static inline void* TryMemMapLow4GB(void* ptr,
+void* MemMap::TryMemMapLow4GB(void* ptr,
                                     size_t page_aligned_byte_count,
                                     int prot,
                                     int flags,
                                     int fd,
                                     off_t offset) {
-  void* actual = mmap(ptr, page_aligned_byte_count, prot, flags, fd, offset);
+  void* actual = TargetMMap(ptr, page_aligned_byte_count, prot, flags, fd, offset);
   if (actual != MAP_FAILED) {
     // Since we didn't use MAP_FIXED the kernel may have mapped it somewhere not in the low
     // 4GB. If this is the case, unmap and retry.
     if (reinterpret_cast<uintptr_t>(actual) + page_aligned_byte_count >= 4 * GB) {
-      munmap(actual, page_aligned_byte_count);
+      TargetMUnmap(actual, page_aligned_byte_count);
       actual = MAP_FAILED;
     }
   }
@@ -237,7 +242,7 @@
 #ifndef __LP64__
   UNUSED(low_4gb);
 #endif
-  use_ashmem = use_ashmem && !kIsTargetLinux;
+  use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia;
   if (byte_count == 0) {
     return new MemMap(name, nullptr, 0, nullptr, 0, prot, false);
   }
@@ -521,7 +526,7 @@
   if (!reuse_) {
     MEMORY_TOOL_MAKE_UNDEFINED(base_begin_, base_size_);
     if (!already_unmapped_) {
-      int result = munmap(base_begin_, base_size_);
+      int result = TargetMUnmap(base_begin_, base_size_);
       if (result == -1) {
         PLOG(FATAL) << "munmap failed";
       }
@@ -565,7 +570,7 @@
 
 MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_prot,
                            std::string* error_msg, bool use_ashmem) {
-  use_ashmem = use_ashmem && !kIsTargetLinux;
+  use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia;
   DCHECK_GE(new_end, Begin());
   DCHECK_LE(new_end, End());
   DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_);
@@ -607,7 +612,7 @@
 
   MEMORY_TOOL_MAKE_UNDEFINED(tail_base_begin, tail_base_size);
   // Unmap/map the tail region.
-  int result = munmap(tail_base_begin, tail_base_size);
+  int result = TargetMUnmap(tail_base_begin, tail_base_size);
   if (result == -1) {
     PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
     *error_msg = StringPrintf("munmap(%p, %zd) failed for '%s'. See process maps in the log.",
@@ -618,12 +623,12 @@
   // calls. Otherwise, libc (or something else) might take this memory
   // region. Note this isn't perfect as there's no way to prevent
   // other threads to try to take this memory region here.
-  uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(tail_base_begin,
-                                                    tail_base_size,
-                                                    tail_prot,
-                                                    flags,
-                                                    fd.get(),
-                                                    0));
+  uint8_t* actual = reinterpret_cast<uint8_t*>(TargetMMap(tail_base_begin,
+                                                          tail_base_size,
+                                                          tail_prot,
+                                                          flags,
+                                                          fd.get(),
+                                                          0));
   if (actual == MAP_FAILED) {
     PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
     *error_msg = StringPrintf("anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0) failed. See process "
@@ -798,6 +803,8 @@
   std::lock_guard<std::mutex> mu(*mem_maps_lock_);
   DCHECK(gMaps == nullptr);
   gMaps = new Maps;
+
+  TargetMMapInit();
 }
 
 void MemMap::Shutdown() {
@@ -829,8 +836,10 @@
       reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) +
                               new_base_size),
       base_size_ - new_base_size);
-  CHECK_EQ(munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_base_size),
-                  base_size_ - new_base_size), 0) << new_base_size << " " << base_size_;
+  CHECK_EQ(TargetMUnmap(reinterpret_cast<void*>(
+                        reinterpret_cast<uintptr_t>(BaseBegin()) + new_base_size),
+                        base_size_ - new_base_size), 0)
+                        << new_base_size << " " << base_size_;
   base_size_ = new_base_size;
   size_ = new_size;
 }
@@ -976,7 +985,7 @@
     if (orig_prot != prot_non_exec) {
       if (mprotect(actual, length, orig_prot) != 0) {
         PLOG(ERROR) << "Could not protect to requested prot: " << orig_prot;
-        munmap(actual, length);
+        TargetMUnmap(actual, length);
         errno = ENOMEM;
         return MAP_FAILED;
       }
@@ -984,14 +993,14 @@
     return actual;
   }
 
-  actual = mmap(addr, length, prot, flags, fd, offset);
+  actual = TargetMMap(addr, length, prot, flags, fd, offset);
 #else
 #if defined(__LP64__)
   if (low_4gb && addr == nullptr) {
     flags |= MAP_32BIT;
   }
 #endif
-  actual = mmap(addr, length, prot, flags, fd, offset);
+  actual = TargetMMap(addr, length, prot, flags, fd, offset);
 #endif
   return actual;
 }
@@ -1067,13 +1076,13 @@
   // Unmap the unaligned parts.
   if (base_begin < aligned_base_begin) {
     MEMORY_TOOL_MAKE_UNDEFINED(base_begin, aligned_base_begin - base_begin);
-    CHECK_EQ(munmap(base_begin, aligned_base_begin - base_begin), 0)
+    CHECK_EQ(TargetMUnmap(base_begin, aligned_base_begin - base_begin), 0)
         << "base_begin=" << reinterpret_cast<void*>(base_begin)
         << " aligned_base_begin=" << reinterpret_cast<void*>(aligned_base_begin);
   }
   if (aligned_base_end < base_end) {
     MEMORY_TOOL_MAKE_UNDEFINED(aligned_base_end, base_end - aligned_base_end);
-    CHECK_EQ(munmap(aligned_base_end, base_end - aligned_base_end), 0)
+    CHECK_EQ(TargetMUnmap(aligned_base_end, base_end - aligned_base_end), 0)
         << "base_end=" << reinterpret_cast<void*>(base_end)
         << " aligned_base_end=" << reinterpret_cast<void*>(aligned_base_end);
   }
diff --git a/libartbase/base/mem_map.h b/libartbase/base/mem_map.h
index 3a324b2..1979357 100644
--- a/libartbase/base/mem_map.h
+++ b/libartbase/base/mem_map.h
@@ -29,10 +29,11 @@
 
 namespace art {
 
-#if defined(__LP64__) && (defined(__aarch64__) || defined(__mips__) || defined(__APPLE__))
+#if defined(__LP64__) && !defined(__Fuchsia__) && \
+    (defined(__aarch64__) || defined(__mips__) || defined(__APPLE__))
 #define USE_ART_LOW_4G_ALLOCATOR 1
 #else
-#if defined(__LP64__) && !defined(__x86_64__)
+#if defined(__LP64__) && !defined(__Fuchsia__) && !defined(__x86_64__)
 #error "Unrecognized 64-bit architecture."
 #endif
 #define USE_ART_LOW_4G_ALLOCATOR 0
@@ -264,6 +265,12 @@
                                              off_t offset)
       REQUIRES(!MemMap::mem_maps_lock_);
 
+  // member function to access real_munmap
+  static bool CheckMapRequest(uint8_t* expected_ptr,
+                              void* actual_ptr,
+                              size_t byte_count,
+                              std::string* error_msg);
+
   const std::string name_;
   uint8_t* begin_;  // Start of data. May be changed by AlignBy.
   size_t size_;  // Length of data.
@@ -284,8 +291,19 @@
 
 #if USE_ART_LOW_4G_ALLOCATOR
   static uintptr_t next_mem_pos_;   // Next memory location to check for low_4g extent.
+
+  static void* TryMemMapLow4GB(void* ptr,
+                               size_t page_aligned_byte_count,
+                               int prot,
+                               int flags,
+                               int fd,
+                               off_t offset);
 #endif
 
+  static void TargetMMapInit();
+  static void* TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off);
+  static int TargetMUnmap(void* start, size_t len);
+
   static std::mutex* mem_maps_lock_;
 
   friend class MemMapTest;  // To allow access to base_begin_ and base_size_.
diff --git a/libartbase/base/mem_map_fuchsia.cc b/libartbase/base/mem_map_fuchsia.cc
new file mode 100644
index 0000000..db31efb
--- /dev/null
+++ b/libartbase/base/mem_map_fuchsia.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mem_map.h"
+#include <sys/mman.h>
+#include "logging.h"
+
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+
+namespace art {
+
+static zx_handle_t fuchsia_lowmem_vmar = ZX_HANDLE_INVALID;
+static zx_vaddr_t fuchsia_lowmem_base = 0;
+static size_t fuchsia_lowmem_size = 0;
+
+static const char map_name[] = "mmap-android";
+static constexpr uintptr_t FUCHSIA_LOWER_MEM_START = 0x80000000;
+static constexpr uintptr_t FUCHSIA_LOWER_MEM_SIZE  = 0x60000000;
+
+void MemMap::TargetMMapInit() {
+  if (fuchsia_lowmem_vmar != ZX_HANDLE_INVALID) {
+    return;
+  }
+
+  zx_info_vmar_t vmarinfo;
+  CHECK_EQ(zx_object_get_info(zx_vmar_root_self(),
+                              ZX_INFO_VMAR,
+                              &vmarinfo,
+                              sizeof(vmarinfo),
+                              NULL,
+                              NULL), ZX_OK) << "could not find info from root vmar";
+
+  uintptr_t lower_mem_start = FUCHSIA_LOWER_MEM_START - vmarinfo.base;
+  fuchsia_lowmem_size = FUCHSIA_LOWER_MEM_SIZE;
+  uint32_t allocflags = ZX_VM_FLAG_CAN_MAP_READ |
+                        ZX_VM_FLAG_CAN_MAP_WRITE |
+                        ZX_VM_FLAG_CAN_MAP_EXECUTE |
+                        ZX_VM_FLAG_SPECIFIC;
+  CHECK_EQ(zx_vmar_allocate(zx_vmar_root_self(),
+                            lower_mem_start,
+                            fuchsia_lowmem_size,
+                            allocflags,
+                            &fuchsia_lowmem_vmar,
+                            &fuchsia_lowmem_base), ZX_OK) << "could not allocate lowmem vmar";
+}
+
+void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
+  zx_status_t status;
+  uintptr_t mem = 0;
+
+  bool mmap_lower = (flags & MAP_32BIT) != 0;
+
+  // for file-based mapping use system library
+  if ((flags & MAP_ANONYMOUS) == 0) {
+    if (start != nullptr) {
+      flags |= MAP_FIXED;
+    }
+    CHECK(!mmap_lower) << "cannot map files into low memory for Fuchsia";
+    return mmap(start, len, prot, flags, fd, fd_off);
+  }
+
+  uint32_t vmarflags = 0;
+  if ((prot & PROT_READ) != 0) {
+    vmarflags |= ZX_VM_FLAG_PERM_READ;
+  }
+  if ((prot & PROT_WRITE) != 0) {
+    vmarflags |= ZX_VM_FLAG_PERM_WRITE;
+  }
+  if ((prot & PROT_EXEC) != 0) {
+    vmarflags |= ZX_VM_FLAG_PERM_EXECUTE;
+  }
+
+  if (len == 0) {
+    errno = EINVAL;
+    return MAP_FAILED;
+  }
+
+  zx_info_vmar_t vmarinfo;
+  size_t vmaroffset = 0;
+  if (start != nullptr) {
+    vmarflags |= ZX_VM_FLAG_SPECIFIC;
+    status = zx_object_get_info((mmap_lower ? fuchsia_lowmem_vmar : zx_vmar_root_self()),
+                                ZX_INFO_VMAR,
+                                &vmarinfo,
+                                sizeof(vmarinfo),
+                                NULL,
+                                NULL);
+    if (status < 0 || reinterpret_cast<uintptr_t>(start) < vmarinfo.base) {
+      errno = EINVAL;
+      return MAP_FAILED;
+    }
+    vmaroffset = reinterpret_cast<uintptr_t>(start) - vmarinfo.base;
+  }
+
+  zx_handle_t vmo;
+  if (zx_vmo_create(len, 0, &vmo) < 0) {
+    errno = ENOMEM;
+    return MAP_FAILED;
+  }
+  zx_vmo_get_size(vmo, &len);
+  zx_object_set_property(vmo, ZX_PROP_NAME, map_name, strlen(map_name));
+
+  if (mmap_lower) {
+    status = zx_vmar_map(fuchsia_lowmem_vmar, vmaroffset, vmo, fd_off, len, vmarflags, &mem);
+  } else {
+    status = zx_vmar_map(zx_vmar_root_self(), vmaroffset, vmo, fd_off, len, vmarflags, &mem);
+  }
+  zx_handle_close(vmo);
+  if (status != ZX_OK) {
+    return MAP_FAILED;
+  }
+
+  return reinterpret_cast<void *>(mem);
+}
+
+int MemMap::TargetMUnmap(void* start, size_t len) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(start);
+  zx_handle_t alloc_vmar = zx_vmar_root_self();
+  if (addr >= fuchsia_lowmem_base && addr < fuchsia_lowmem_base + fuchsia_lowmem_size) {
+    alloc_vmar = fuchsia_lowmem_vmar;
+  }
+  zx_status_t status = zx_vmar_unmap(alloc_vmar, addr, len);
+  if (status < 0) {
+    errno = EINVAL;
+    return -1;
+  }
+  return 0;
+}
+
+}  // namespace art
diff --git a/libartbase/base/mem_map_unix.cc b/libartbase/base/mem_map_unix.cc
new file mode 100644
index 0000000..601b049
--- /dev/null
+++ b/libartbase/base/mem_map_unix.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mem_map.h"
+
+#include <sys/mman.h>
+
+namespace art {
+
+void MemMap::TargetMMapInit() {
+  // no-op for unix
+}
+
+void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
+  return mmap(start, len, prot, flags, fd, fd_off);
+}
+
+int MemMap::TargetMUnmap(void* start, size_t len) {
+  return munmap(start, len);
+}
+
+}  // namespace art
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index b010650..b1cd5c0 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -167,8 +167,8 @@
 
   // Generating debug information is for using the Linux perf tool on
   // host which does not work with ashmem.
-  // Also, target linux does not support ashmem.
-  bool use_ashmem = !generate_debug_info && !kIsTargetLinux;
+  // Also, targets linux and fuchsia do not support ashmem.
+  bool use_ashmem = !generate_debug_info && !kIsTargetLinux && !kIsTargetFuchsia;
 
   // With 'perf', we want a 1-1 mapping between an address and a method.
   bool garbage_collect_code = !generate_debug_info;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 2b05b0e..9355ae7 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1063,7 +1063,8 @@
     dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
 #else
     UNUSED(oat_file_begin);
-    static_assert(!kIsTargetBuild || kIsTargetLinux, "host_dlopen_handles_ will leak handles");
+    static_assert(!kIsTargetBuild || kIsTargetLinux || kIsTargetFuchsia,
+                  "host_dlopen_handles_ will leak handles");
     MutexLock mu(Thread::Current(), *Locks::host_dlopen_handles_lock_);
     dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW);
     if (dlopen_handle_ != nullptr) {