mozilla-aarch64-48bit-va.patch
branchfirefox47
changeset 919 6838f0c032f8
equal deleted inserted replaced
918:0f93e8da34b6 919:6838f0c032f8
       
     1 
       
     2 # HG changeset patch
       
     3 # User Zheng Xu <zheng.xu@linaro.org>
       
     4 # Date 1464657720 -7200
       
     5 # Node ID dfaafbaaa2919a033c4c0abdd5830f4ea413bed6
       
     6 # Parent  499f16ca85ec48d1896a1633730715f32bd62140
       
     7 Bug 1143022 - Manually mmap on arm64 to ensure high 17 bits are clear. r=ehoogeveen
       
     8 
       
     9 There might be 48-bit VA on arm64 depending on kernel configuration.
       
    10 Manually mmap heap memory to align with the assumption made by JS engine.
       
    11 
       
    12 diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp
       
    13 --- a/js/src/gc/Memory.cpp
       
    14 +++ b/js/src/gc/Memory.cpp
       
    15 @@ -430,17 +430,17 @@ InitMemorySubsystem()
       
    16      if (pageSize == 0)
       
    17          pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE));
       
    18  }
       
    19  
       
    20  static inline void*
       
    21  MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE,
       
    22              int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0)
       
    23  {
       
    24 -#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
       
    25 +#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__)
       
    26      MOZ_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0);
       
    27  #endif
       
    28      void* region = mmap(desired, length, prot, flags, fd, offset);
       
    29      if (region == MAP_FAILED)
       
    30          return nullptr;
       
    31      /*
       
    32       * mmap treats the given address as a hint unless the MAP_FIXED flag is
       
    33       * used (which isn't usually what you want, as this overrides existing
       
    34 @@ -480,16 +480,51 @@ MapMemory(size_t length, int prot = PROT
       
    35       * as out of memory.
       
    36       */
       
    37      if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) {
       
    38          if (munmap(region, length))
       
    39              MOZ_ASSERT(errno == ENOMEM);
       
    40          return nullptr;
       
    41      }
       
    42      return region;
       
    43 +#elif defined(__aarch64__)
       
    44 +   /*
       
    45 +    * There might be similar virtual address issue on arm64 which depends on
       
    46 +    * hardware and kernel configurations. But the work around is slightly
       
    47 +    * different due to the different mmap behavior.
       
    48 +    *
       
    49 +    * TODO: Merge with the above code block if this implementation works for
       
    50 +    * ia64 and sparc64.
       
    51 +    */
       
    52 +    const uintptr_t start = UINT64_C(0x0000070000000000);
       
    53 +    const uintptr_t end   = UINT64_C(0x0000800000000000);
       
    54 +    const uintptr_t step  = ChunkSize;
       
    55 +   /*
       
    56 +    * Optimization options if there are too many retries in practice:
       
    57 +    * 1. Examine /proc/self/maps to find an available address. This file is
       
    58 +    *    not always available, however. In addition, even if we examine
       
    59 +    *    /proc/self/maps, we may still need to retry several times due to
       
    60 +    *    racing with other threads.
       
    61 +    * 2. Use a global/static variable with lock to track the addresses we have
       
    62 +    *    allocated or tried.
       
    63 +    */
       
    64 +    uintptr_t hint;
       
    65 +    void* region = MAP_FAILED;
       
    66 +    for (hint = start; region == MAP_FAILED && hint + length <= end; hint += step) {
       
    67 +        region = mmap((void*)hint, length, prot, flags, fd, offset);
       
    68 +        if (region != MAP_FAILED) {
       
    69 +            if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) {
       
    70 +                if (munmap(region, length)) {
       
    71 +                    MOZ_ASSERT(errno == ENOMEM);
       
    72 +                }
       
    73 +                region = MAP_FAILED;
       
    74 +            }
       
    75 +        }
       
    76 +    }
       
    77 +    return region == MAP_FAILED ? nullptr : region;
       
    78  #else
       
    79      void* region = MozTaggedAnonymousMmap(nullptr, length, prot, flags, fd, offset, "js-gc-heap");
       
    80      if (region == MAP_FAILED)
       
    81          return nullptr;
       
    82      return region;
       
    83  #endif
       
    84  }
       
    85  
       
    86 diff --git a/js/src/jsapi-tests/testGCAllocator.cpp b/js/src/jsapi-tests/testGCAllocator.cpp
       
    87 --- a/js/src/jsapi-tests/testGCAllocator.cpp
       
    88 +++ b/js/src/jsapi-tests/testGCAllocator.cpp
       
    89 @@ -307,48 +307,72 @@ void* mapMemoryAt(void* desired, size_t 
       
    90  void* mapMemory(size_t length) { return nullptr; }
       
    91  void unmapPages(void* p, size_t size) { }
       
    92  
       
    93  #elif defined(XP_UNIX)
       
    94  
       
    95  void*
       
    96  mapMemoryAt(void* desired, size_t length)
       
    97  {
       
    98 -#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
       
    99 +#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__)
       
   100      MOZ_RELEASE_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0);
       
   101  #endif
       
   102      void* region = mmap(desired, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
       
   103      if (region == MAP_FAILED)
       
   104          return nullptr;
       
   105      if (region != desired) {
       
   106          if (munmap(region, length))
       
   107              MOZ_RELEASE_ASSERT(errno == ENOMEM);
       
   108          return nullptr;
       
   109      }
       
   110      return region;
       
   111  }
       
   112  
       
   113  void*
       
   114  mapMemory(size_t length)
       
   115  {
       
   116 -    void* hint = nullptr;
       
   117 +    int prot = PROT_READ | PROT_WRITE;
       
   118 +    int flags = MAP_PRIVATE | MAP_ANON;
       
   119 +    int fd = -1;
       
   120 +    off_t offset = 0;
       
   121 +    // The test code must be aligned with the implementation in gc/Memory.cpp.
       
   122  #if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
       
   123 -    hint = (void*)0x0000070000000000ULL;
       
   124 -#endif
       
   125 -    void* region = mmap(hint, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
       
   126 +    void* region = mmap((void*)0x0000070000000000, length, prot, flags, fd, offset);
       
   127      if (region == MAP_FAILED)
       
   128          return nullptr;
       
   129 -#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__))
       
   130 -    if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000ULL) {
       
   131 +    if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) {
       
   132          if (munmap(region, length))
       
   133              MOZ_RELEASE_ASSERT(errno == ENOMEM);
       
   134          return nullptr;
       
   135      }
       
   136 +    return region;
       
   137 +#elif defined(__aarch64__)
       
   138 +    const uintptr_t start = UINT64_C(0x0000070000000000);
       
   139 +    const uintptr_t end   = UINT64_C(0x0000800000000000);
       
   140 +    const uintptr_t step  = ChunkSize;
       
   141 +    uintptr_t hint;
       
   142 +    void* region = MAP_FAILED;
       
   143 +    for (hint = start; region == MAP_FAILED && hint + length <= end; hint += step) {
       
   144 +        region = mmap((void*)hint, length, prot, flags, fd, offset);
       
   145 +        if (region != MAP_FAILED) {
       
   146 +            if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) {
       
   147 +                if (munmap(region, length)) {
       
   148 +                    MOZ_RELEASE_ASSERT(errno == ENOMEM);
       
   149 +                }
       
   150 +                region = MAP_FAILED;
       
   151 +            }
       
   152 +        }
       
   153 +    }
       
   154 +    return region == MAP_FAILED ? nullptr : region;
       
   155 +#else
       
   156 +    void* region = mmap(nullptr, length, prot, flags, fd, offset);
       
   157 +    if (region == MAP_FAILED)
       
   158 +        return nullptr;
       
   159 +    return region;
       
   160  #endif
       
   161 -    return region;
       
   162  }
       
   163  
       
   164  void
       
   165  unmapPages(void* p, size_t size)
       
   166  {
       
   167      if (munmap(p, size))
       
   168          MOZ_RELEASE_ASSERT(errno == ENOMEM);
       
   169  }
       
   170