source: webkit/trunk/JavaScriptCore/wtf/TCSystemAlloc.cpp@ 38975

Last change on this file since 38975 was 38857, checked in by [email protected], 16 years ago

2008-11-29 Gavin Barraclough <[email protected]>

Reviewed by Camron Zwarich.

Enable WREC on PLATFORM(X86_64). This change predominantly requires changes to the
WREC::Generator::generateEnter method to support the x86-64 ABI, and addition of
support for a limited number of quadword operations in the X86Assembler.

This patch will cause the JS heap to be allocated with RWX permissions on 64-bit Mac
platforms. This is a regression with respect to previous 64-bit behaviour, but is no
more permissive than on 32-bit builds. This issue should be addressed at some point.
(This is tracked by bug #21783.)

https://bugs.webkit.org/show_bug.cgi?id=22554
Greater than 4x speedup on regexp-dna, on x86-64.

  • assembler/MacroAssembler.h: (JSC::MacroAssembler::addPtr): (JSC::MacroAssembler::loadPtr): (JSC::MacroAssembler::storePtr): (JSC::MacroAssembler::pop): (JSC::MacroAssembler::push): (JSC::MacroAssembler::move):
  • assembler/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::movq_rr): (JSC::X86Assembler::addl_i8m): (JSC::X86Assembler::addl_i32r): (JSC::X86Assembler::addq_i8r): (JSC::X86Assembler::addq_i32r): (JSC::X86Assembler::movq_mr): (JSC::X86Assembler::movq_rm):
  • wrec/WREC.h:
  • wrec/WRECGenerator.cpp: (JSC::WREC::Generator::generateEnter): (JSC::WREC::Generator::generateReturnSuccess): (JSC::WREC::Generator::generateReturnFailure):
  • wtf/Platform.h:
  • wtf/TCSystemAlloc.cpp:
  • Property svn:eol-style set to native
File size: 13.0 KB
Line 
1// Copyright (c) 2005, 2007, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Sanjay Ghemawat
32
33#include "config.h"
34#if HAVE(STDINT_H)
35#include <stdint.h>
36#elif HAVE(INTTYPES_H)
37#include <inttypes.h>
38#else
39#include <sys/types.h>
40#endif
41#if PLATFORM(WIN_OS)
42#include "windows.h"
43#else
44#include <errno.h>
45#include <unistd.h>
46#include <sys/mman.h>
47#endif
48#include <fcntl.h>
49#include "Assertions.h"
50#include "TCSystemAlloc.h"
51#include "TCSpinLock.h"
52#include "UnusedParam.h"
53
54#if HAVE(MMAP)
55static const int cProtFlags = PROT_READ | PROT_WRITE
56#if ENABLE(ASSEMBLER) && (PLATFORM(GTK) || (PLATFORM(MAC) && PLATFORM(X86_64)))
57 | PROT_EXEC
58#endif
59 ;
60#endif
61
62#ifndef MAP_ANONYMOUS
63#define MAP_ANONYMOUS MAP_ANON
64#endif
65
66// Structure for discovering alignment
67union MemoryAligner {
68 void* p;
69 double d;
70 size_t s;
71};
72
73static SpinLock spinlock = SPINLOCK_INITIALIZER;
74
75// Page size is initialized on demand
76static size_t pagesize = 0;
77
78// Configuration parameters.
79//
80// if use_devmem is true, either use_sbrk or use_mmap must also be true.
81// For 2.2 kernels, it looks like the sbrk address space (500MBish) and
82// the mmap address space (1300MBish) are disjoint, so we need both allocators
83// to get as much virtual memory as possible.
84#ifndef WTF_CHANGES
85static bool use_devmem = false;
86#endif
87
88#if HAVE(SBRK)
89static bool use_sbrk = false;
90#endif
91
92#if HAVE(MMAP)
93static bool use_mmap = true;
94#endif
95
96#if HAVE(VIRTUALALLOC)
97static bool use_VirtualAlloc = true;
98#endif
99
100// Flags to keep us from retrying allocators that failed.
101static bool devmem_failure = false;
102static bool sbrk_failure = false;
103static bool mmap_failure = false;
104static bool VirtualAlloc_failure = false;
105
106#ifndef WTF_CHANGES
107DEFINE_int32(malloc_devmem_start, 0,
108 "Physical memory starting location in MB for /dev/mem allocation."
109 " Setting this to 0 disables /dev/mem allocation");
110DEFINE_int32(malloc_devmem_limit, 0,
111 "Physical memory limit location in MB for /dev/mem allocation."
112 " Setting this to 0 means no limit.");
113#else
114static const int32_t FLAGS_malloc_devmem_start = 0;
115static const int32_t FLAGS_malloc_devmem_limit = 0;
116#endif
117
118#if HAVE(SBRK)
119
120static void* TrySbrk(size_t size, size_t *actual_size, size_t alignment) {
121 size = ((size + alignment - 1) / alignment) * alignment;
122
123 // could theoretically return the "extra" bytes here, but this
124 // is simple and correct.
125 if (actual_size)
126 *actual_size = size;
127
128 void* result = sbrk(size);
129 if (result == reinterpret_cast<void*>(-1)) {
130 sbrk_failure = true;
131 return NULL;
132 }
133
134 // Is it aligned?
135 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
136 if ((ptr & (alignment-1)) == 0) return result;
137
138 // Try to get more memory for alignment
139 size_t extra = alignment - (ptr & (alignment-1));
140 void* r2 = sbrk(extra);
141 if (reinterpret_cast<uintptr_t>(r2) == (ptr + size)) {
142 // Contiguous with previous result
143 return reinterpret_cast<void*>(ptr + extra);
144 }
145
146 // Give up and ask for "size + alignment - 1" bytes so
147 // that we can find an aligned region within it.
148 result = sbrk(size + alignment - 1);
149 if (result == reinterpret_cast<void*>(-1)) {
150 sbrk_failure = true;
151 return NULL;
152 }
153 ptr = reinterpret_cast<uintptr_t>(result);
154 if ((ptr & (alignment-1)) != 0) {
155 ptr += alignment - (ptr & (alignment-1));
156 }
157 return reinterpret_cast<void*>(ptr);
158}
159
160#endif /* HAVE(SBRK) */
161
162#if HAVE(MMAP)
163
164static void* TryMmap(size_t size, size_t *actual_size, size_t alignment) {
165 // Enforce page alignment
166 if (pagesize == 0) pagesize = getpagesize();
167 if (alignment < pagesize) alignment = pagesize;
168 size = ((size + alignment - 1) / alignment) * alignment;
169
170 // could theoretically return the "extra" bytes here, but this
171 // is simple and correct.
172 if (actual_size)
173 *actual_size = size;
174
175 // Ask for extra memory if alignment > pagesize
176 size_t extra = 0;
177 if (alignment > pagesize) {
178 extra = alignment - pagesize;
179 }
180 void* result = mmap(NULL, size + extra,
181 cProtFlags,
182 MAP_PRIVATE|MAP_ANONYMOUS,
183 -1, 0);
184 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
185 mmap_failure = true;
186 return NULL;
187 }
188
189 // Adjust the return memory so it is aligned
190 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
191 size_t adjust = 0;
192 if ((ptr & (alignment - 1)) != 0) {
193 adjust = alignment - (ptr & (alignment - 1));
194 }
195
196 // Return the unused memory to the system
197 if (adjust > 0) {
198 munmap(reinterpret_cast<void*>(ptr), adjust);
199 }
200 if (adjust < extra) {
201 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
202 }
203
204 ptr += adjust;
205 return reinterpret_cast<void*>(ptr);
206}
207
208#endif /* HAVE(MMAP) */
209
210#if HAVE(VIRTUALALLOC)
211
212static void* TryVirtualAlloc(size_t size, size_t *actual_size, size_t alignment) {
213 // Enforce page alignment
214 if (pagesize == 0) {
215 SYSTEM_INFO system_info;
216 GetSystemInfo(&system_info);
217 pagesize = system_info.dwPageSize;
218 }
219
220 if (alignment < pagesize) alignment = pagesize;
221 size = ((size + alignment - 1) / alignment) * alignment;
222
223 // could theoretically return the "extra" bytes here, but this
224 // is simple and correct.
225 if (actual_size)
226 *actual_size = size;
227
228 // Ask for extra memory if alignment > pagesize
229 size_t extra = 0;
230 if (alignment > pagesize) {
231 extra = alignment - pagesize;
232 }
233 void* result = VirtualAlloc(NULL, size + extra,
234 MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
235 PAGE_EXECUTE_READWRITE);
236
237 if (result == NULL) {
238 VirtualAlloc_failure = true;
239 return NULL;
240 }
241
242 // Adjust the return memory so it is aligned
243 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
244 size_t adjust = 0;
245 if ((ptr & (alignment - 1)) != 0) {
246 adjust = alignment - (ptr & (alignment - 1));
247 }
248
249 // Return the unused memory to the system - we'd like to release but the best we can do
250 // is decommit, since Windows only lets you free the whole allocation.
251 if (adjust > 0) {
252 VirtualFree(reinterpret_cast<void*>(ptr), adjust, MEM_DECOMMIT);
253 }
254 if (adjust < extra) {
255 VirtualFree(reinterpret_cast<void*>(ptr + adjust + size), extra-adjust, MEM_DECOMMIT);
256 }
257
258 ptr += adjust;
259 return reinterpret_cast<void*>(ptr);
260}
261
262#endif /* HAVE(MMAP) */
263
264#ifndef WTF_CHANGES
265static void* TryDevMem(size_t size, size_t *actual_size, size_t alignment) {
266 static bool initialized = false;
267 static off_t physmem_base; // next physical memory address to allocate
268 static off_t physmem_limit; // maximum physical address allowed
269 static int physmem_fd; // file descriptor for /dev/mem
270
271 // Check if we should use /dev/mem allocation. Note that it may take
272 // a while to get this flag initialized, so meanwhile we fall back to
273 // the next allocator. (It looks like 7MB gets allocated before
274 // this flag gets initialized -khr.)
275 if (FLAGS_malloc_devmem_start == 0) {
276 // NOTE: not a devmem_failure - we'd like TCMalloc_SystemAlloc to
277 // try us again next time.
278 return NULL;
279 }
280
281 if (!initialized) {
282 physmem_fd = open("/dev/mem", O_RDWR);
283 if (physmem_fd < 0) {
284 devmem_failure = true;
285 return NULL;
286 }
287 physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL;
288 physmem_limit = FLAGS_malloc_devmem_limit*1024LL*1024LL;
289 initialized = true;
290 }
291
292 // Enforce page alignment
293 if (pagesize == 0) pagesize = getpagesize();
294 if (alignment < pagesize) alignment = pagesize;
295 size = ((size + alignment - 1) / alignment) * alignment;
296
297 // could theoretically return the "extra" bytes here, but this
298 // is simple and correct.
299 if (actual_size)
300 *actual_size = size;
301
302 // Ask for extra memory if alignment > pagesize
303 size_t extra = 0;
304 if (alignment > pagesize) {
305 extra = alignment - pagesize;
306 }
307
308 // check to see if we have any memory left
309 if (physmem_limit != 0 && physmem_base + size + extra > physmem_limit) {
310 devmem_failure = true;
311 return NULL;
312 }
313 void *result = mmap(0, size + extra, cProtFlags,
314 MAP_SHARED, physmem_fd, physmem_base);
315 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
316 devmem_failure = true;
317 return NULL;
318 }
319 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
320
321 // Adjust the return memory so it is aligned
322 size_t adjust = 0;
323 if ((ptr & (alignment - 1)) != 0) {
324 adjust = alignment - (ptr & (alignment - 1));
325 }
326
327 // Return the unused virtual memory to the system
328 if (adjust > 0) {
329 munmap(reinterpret_cast<void*>(ptr), adjust);
330 }
331 if (adjust < extra) {
332 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
333 }
334
335 ptr += adjust;
336 physmem_base += adjust + size;
337
338 return reinterpret_cast<void*>(ptr);
339}
340#endif
341
342void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) {
343 // Discard requests that overflow
344 if (size + alignment < size) return NULL;
345
346 SpinLockHolder lock_holder(&spinlock);
347
348 // Enforce minimum alignment
349 if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);
350
351 // Try twice, once avoiding allocators that failed before, and once
352 // more trying all allocators even if they failed before.
353 for (int i = 0; i < 2; i++) {
354
355#ifndef WTF_CHANGES
356 if (use_devmem && !devmem_failure) {
357 void* result = TryDevMem(size, actual_size, alignment);
358 if (result != NULL) return result;
359 }
360#endif
361
362#if HAVE(SBRK)
363 if (use_sbrk && !sbrk_failure) {
364 void* result = TrySbrk(size, actual_size, alignment);
365 if (result != NULL) return result;
366 }
367#endif
368
369#if HAVE(MMAP)
370 if (use_mmap && !mmap_failure) {
371 void* result = TryMmap(size, actual_size, alignment);
372 if (result != NULL) return result;
373 }
374#endif
375
376#if HAVE(VIRTUALALLOC)
377 if (use_VirtualAlloc && !VirtualAlloc_failure) {
378 void* result = TryVirtualAlloc(size, actual_size, alignment);
379 if (result != NULL) return result;
380 }
381#endif
382
383 // nothing worked - reset failure flags and try again
384 devmem_failure = false;
385 sbrk_failure = false;
386 mmap_failure = false;
387 VirtualAlloc_failure = false;
388 }
389 return NULL;
390}
391
392void TCMalloc_SystemRelease(void* start, size_t length)
393{
394 UNUSED_PARAM(start);
395 UNUSED_PARAM(length);
396#if HAVE(MADV_DONTNEED)
397 if (FLAGS_malloc_devmem_start) {
398 // It's not safe to use MADV_DONTNEED if we've been mapping
399 // /dev/mem for heap memory
400 return;
401 }
402 if (pagesize == 0) pagesize = getpagesize();
403 const size_t pagemask = pagesize - 1;
404
405 size_t new_start = reinterpret_cast<size_t>(start);
406 size_t end = new_start + length;
407 size_t new_end = end;
408
409 // Round up the starting address and round down the ending address
410 // to be page aligned:
411 new_start = (new_start + pagesize - 1) & ~pagemask;
412 new_end = new_end & ~pagemask;
413
414 ASSERT((new_start & pagemask) == 0);
415 ASSERT((new_end & pagemask) == 0);
416 ASSERT(new_start >= reinterpret_cast<size_t>(start));
417 ASSERT(new_end <= end);
418
419 if (new_end > new_start) {
420 // Note -- ignoring most return codes, because if this fails it
421 // doesn't matter...
422 while (madvise(reinterpret_cast<char*>(new_start), new_end - new_start,
423 MADV_DONTNEED) == -1 &&
424 errno == EAGAIN) {
425 // NOP
426 }
427 return;
428 }
429#endif
430
431#if HAVE(MMAP)
432 void *newAddress = mmap(start, length, cProtFlags, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
433 UNUSED_PARAM(newAddress);
434 // If the mmap failed then that's ok, we just won't return the memory to the system.
435 ASSERT(newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED));
436 return;
437#endif
438}
439
440#if HAVE(VIRTUALALLOC)
441void TCMalloc_SystemCommit(void* start, size_t length)
442{
443 UNUSED_PARAM(start);
444 UNUSED_PARAM(length);
445}
446#endif
Note: See TracBrowser for help on using the repository browser.