|
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 |