~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/gc/Memory.cpp

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 * vim: set ts=8 sw=4 et tw=78:
 
3
 *
 
4
 * This Source Code Form is subject to the terms of the Mozilla Public
 
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 
6
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
7
 
 
8
#include "mozilla/Assertions.h"
 
9
 
 
10
#include "jstypes.h"
 
11
 
 
12
#include "js/Utility.h"
 
13
#include "gc/Memory.h"
 
14
 
 
15
namespace js {
 
16
namespace gc {
 
17
 
 
18
#if defined(XP_WIN)
 
19
#include "jswin.h"
 
20
#include <psapi.h>
 
21
 
 
22
static size_t AllocationGranularity = 0;
 
23
 
 
24
void
 
25
InitMemorySubsystem()
 
26
{
 
27
    SYSTEM_INFO sysinfo;
 
28
    GetSystemInfo(&sysinfo);
 
29
    if (sysinfo.dwPageSize != PageSize)
 
30
        MOZ_CRASH();
 
31
    AllocationGranularity = sysinfo.dwAllocationGranularity;
 
32
}
 
33
 
 
34
void *
 
35
MapAlignedPages(size_t size, size_t alignment)
 
36
{
 
37
    JS_ASSERT(size >= alignment);
 
38
    JS_ASSERT(size % alignment == 0);
 
39
    JS_ASSERT(size % PageSize == 0);
 
40
    JS_ASSERT(alignment % AllocationGranularity == 0);
 
41
 
 
42
    /* Special case: If we want allocation alignment, no further work is needed. */
 
43
    if (alignment == AllocationGranularity) {
 
44
        return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
45
    }
 
46
 
 
47
    /*
 
48
     * Windows requires that there be a 1:1 mapping between VM allocation
 
49
     * and deallocation operations.  Therefore, take care here to acquire the
 
50
     * final result via one mapping operation.  This means unmapping any
 
51
     * preliminary result that is not correctly aligned.
 
52
     */
 
53
    void *p = NULL;
 
54
    while (!p) {
 
55
        /*
 
56
         * Over-allocate in order to map a memory region that is
 
57
         * definitely large enough then deallocate and allocate again the
 
58
         * correct sizee, within the over-sized mapping.
 
59
         *
 
60
         * Since we're going to unmap the whole thing anyway, the first
 
61
         * mapping doesn't have to commit pages.
 
62
         */
 
63
        p = VirtualAlloc(NULL, size * 2, MEM_RESERVE, PAGE_READWRITE);
 
64
        if (!p)
 
65
            return NULL;
 
66
        void *chunkStart = (void *)(uintptr_t(p) + (alignment - (uintptr_t(p) % alignment)));
 
67
        UnmapPages(p, size * 2);
 
68
        p = VirtualAlloc(chunkStart, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
69
 
 
70
        /* Failure here indicates a race with another thread, so try again. */
 
71
    }
 
72
 
 
73
    JS_ASSERT(uintptr_t(p) % alignment == 0);
 
74
    return p;
 
75
}
 
76
 
 
77
void
 
78
UnmapPages(void *p, size_t size)
 
79
{
 
80
    JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE));
 
81
}
 
82
 
 
83
bool
 
84
MarkPagesUnused(void *p, size_t size)
 
85
{
 
86
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
87
    LPVOID p2 = VirtualAlloc(p, size, MEM_RESET, PAGE_READWRITE);
 
88
    return p2 == p;
 
89
}
 
90
 
 
91
bool
 
92
MarkPagesInUse(void *p, size_t size)
 
93
{
 
94
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
95
    return true;
 
96
}
 
97
 
 
98
size_t
 
99
GetPageFaultCount()
 
100
{
 
101
    PROCESS_MEMORY_COUNTERS pmc;
 
102
    if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
 
103
        return 0;
 
104
    return pmc.PageFaultCount;
 
105
}
 
106
 
 
107
#elif defined(XP_OS2)
 
108
 
 
109
#define INCL_DOSMEMMGR
 
110
#include <os2.h>
 
111
 
 
112
#define JS_GC_HAS_MAP_ALIGN 1
 
113
#define OS2_MAX_RECURSIONS  16
 
114
 
 
115
void
 
116
InitMemorySubsystem()
 
117
{
 
118
}
 
119
 
 
120
void
 
121
UnmapPages(void *addr, size_t size)
 
122
{
 
123
    if (!DosFreeMem(addr))
 
124
        return;
 
125
 
 
126
    /*
 
127
     * If DosFreeMem() failed, 'addr' is probably part of an "expensive"
 
128
     * allocation, so calculate the base address and try again.
 
129
     */
 
130
    unsigned long cb = 2 * size;
 
131
    unsigned long flags;
 
132
    if (DosQueryMem(addr, &cb, &flags) || cb < size)
 
133
        return;
 
134
 
 
135
    uintptr_t base = reinterpret_cast<uintptr_t>(addr) - ((2 * size) - cb);
 
136
    DosFreeMem(reinterpret_cast<void*>(base));
 
137
 
 
138
    return;
 
139
}
 
140
 
 
141
static void *
 
142
MapAlignedPagesRecursively(size_t size, size_t alignment, int& recursions)
 
143
{
 
144
    if (++recursions >= OS2_MAX_RECURSIONS)
 
145
        return NULL;
 
146
 
 
147
    void *tmp;
 
148
    if (DosAllocMem(&tmp, size,
 
149
                    OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) {
 
150
        JS_ALWAYS_TRUE(DosAllocMem(&tmp, size,
 
151
                                   PAG_COMMIT | PAG_READ | PAG_WRITE) == 0);
 
152
    }
 
153
    size_t offset = reinterpret_cast<uintptr_t>(tmp) & (alignment - 1);
 
154
    if (!offset)
 
155
        return tmp;
 
156
 
 
157
    /*
 
158
     * If there are 'filler' bytes of free space above 'tmp', free 'tmp',
 
159
     * then reallocate it as a 'filler'-sized block;  assuming we're not
 
160
     * in a race with another thread, the next recursion should succeed.
 
161
     */
 
162
    size_t filler = size + alignment - offset;
 
163
    unsigned long cb = filler;
 
164
    unsigned long flags = 0;
 
165
    unsigned long rc = DosQueryMem(&(static_cast<char*>(tmp))[size],
 
166
                                   &cb, &flags);
 
167
    if (!rc && (flags & PAG_FREE) && cb >= filler) {
 
168
        UnmapPages(tmp, 0);
 
169
        if (DosAllocMem(&tmp, filler,
 
170
                        OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) {
 
171
            JS_ALWAYS_TRUE(DosAllocMem(&tmp, filler,
 
172
                                       PAG_COMMIT | PAG_READ | PAG_WRITE) == 0);
 
173
        }
 
174
    }
 
175
 
 
176
    void *p = MapAlignedPagesRecursively(size, alignment, recursions);
 
177
    UnmapPages(tmp, 0);
 
178
 
 
179
    return p;
 
180
}
 
181
 
 
182
void *
 
183
MapAlignedPages(size_t size, size_t alignment)
 
184
{
 
185
    JS_ASSERT(size >= alignment);
 
186
    JS_ASSERT(size % alignment == 0);
 
187
    JS_ASSERT(size % PageSize == 0);
 
188
    JS_ASSERT(alignment % PageSize == 0);
 
189
 
 
190
    int recursions = -1;
 
191
 
 
192
    /*
 
193
     * Make up to OS2_MAX_RECURSIONS attempts to get an aligned block
 
194
     * of the right size by recursively allocating blocks of unaligned
 
195
     * free memory until only an aligned allocation is possible.
 
196
     */
 
197
    void *p = MapAlignedPagesRecursively(size, alignment, recursions);
 
198
    if (p)
 
199
        return p;
 
200
 
 
201
    /*
 
202
     * If memory is heavily fragmented, the recursive strategy may fail;
 
203
     * instead, use the "expensive" strategy:  allocate twice as much
 
204
     * as requested and return an aligned address within this block.
 
205
     */
 
206
    if (DosAllocMem(&p, 2 * size,
 
207
                    OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) {
 
208
        JS_ALWAYS_TRUE(DosAllocMem(&p, 2 * size,
 
209
                                   PAG_COMMIT | PAG_READ | PAG_WRITE) == 0);
 
210
    }
 
211
 
 
212
    uintptr_t addr = reinterpret_cast<uintptr_t>(p);
 
213
    addr = (addr + (alignment - 1)) & ~(alignment - 1);
 
214
 
 
215
    return reinterpret_cast<void *>(addr);
 
216
}
 
217
 
 
218
bool
 
219
MarkPagesUnused(void *p, size_t size)
 
220
{
 
221
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
222
    return true;
 
223
}
 
224
 
 
225
bool
 
226
MarkPagesInUse(void *p, size_t size)
 
227
{
 
228
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
229
    return true;
 
230
}
 
231
 
 
232
size_t
 
233
GetPageFaultCount()
 
234
{
 
235
    return 0;
 
236
}
 
237
 
 
238
#elif defined(SOLARIS)
 
239
 
 
240
#include <sys/mman.h>
 
241
#include <unistd.h>
 
242
 
 
243
#ifndef MAP_NOSYNC
 
244
# define MAP_NOSYNC 0
 
245
#endif
 
246
 
 
247
void
 
248
InitMemorySubsystem()
 
249
{
 
250
}
 
251
 
 
252
void *
 
253
MapAlignedPages(size_t size, size_t alignment)
 
254
{
 
255
    JS_ASSERT(size >= alignment);
 
256
    JS_ASSERT(size % alignment == 0);
 
257
    JS_ASSERT(size % PageSize == 0);
 
258
    JS_ASSERT(alignment % PageSize == 0);
 
259
 
 
260
    int prot = PROT_READ | PROT_WRITE;
 
261
    int flags = MAP_PRIVATE | MAP_ANON | MAP_ALIGN | MAP_NOSYNC;
 
262
 
 
263
    void *p = mmap((caddr_t)alignment, size, prot, flags, -1, 0);
 
264
    if (p == MAP_FAILED)
 
265
        return NULL;
 
266
    return p;
 
267
}
 
268
 
 
269
void
 
270
UnmapPages(void *p, size_t size)
 
271
{
 
272
    JS_ALWAYS_TRUE(0 == munmap((caddr_t)p, size));
 
273
}
 
274
 
 
275
bool
 
276
MarkPagesUnused(void *p, size_t size)
 
277
{
 
278
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
279
    return true;
 
280
}
 
281
 
 
282
bool
 
283
MarkPagesInUse(void *p, size_t size)
 
284
{
 
285
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
286
    return true;
 
287
}
 
288
 
 
289
size_t
 
290
GetPageFaultCount()
 
291
{
 
292
    return 0;
 
293
}
 
294
 
 
295
#elif defined(XP_UNIX) || defined(XP_MACOSX) || defined(DARWIN)
 
296
 
 
297
#include <sys/mman.h>
 
298
#include <sys/time.h>
 
299
#include <sys/resource.h>
 
300
#include <unistd.h>
 
301
 
 
302
void
 
303
InitMemorySubsystem()
 
304
{
 
305
    if (size_t(sysconf(_SC_PAGESIZE)) != PageSize)
 
306
        MOZ_CRASH();
 
307
}
 
308
 
 
309
void *
 
310
MapAlignedPages(size_t size, size_t alignment)
 
311
{
 
312
    JS_ASSERT(size >= alignment);
 
313
    JS_ASSERT(size % alignment == 0);
 
314
    JS_ASSERT(size % PageSize == 0);
 
315
    JS_ASSERT(alignment % PageSize == 0);
 
316
 
 
317
    int prot = PROT_READ | PROT_WRITE;
 
318
    int flags = MAP_PRIVATE | MAP_ANON;
 
319
 
 
320
    /* Special case: If we want page alignment, no further work is needed. */
 
321
    if (alignment == PageSize) {
 
322
        return mmap(NULL, size, prot, flags, -1, 0);
 
323
    }
 
324
 
 
325
    /* Overallocate and unmap the region's edges. */
 
326
    size_t reqSize = Min(size + 2 * alignment, 2 * size);
 
327
    void *region = mmap(NULL, reqSize, prot, flags, -1, 0);
 
328
    if (region == MAP_FAILED)
 
329
        return NULL;
 
330
 
 
331
    uintptr_t regionEnd = uintptr_t(region) + reqSize;
 
332
    uintptr_t offset = uintptr_t(region) % alignment;
 
333
    JS_ASSERT(offset < reqSize - size);
 
334
 
 
335
    void *front = (void *)(uintptr_t(region) + (alignment - offset));
 
336
    void *end = (void *)(uintptr_t(front) + size);
 
337
    if (front != region)
 
338
        JS_ALWAYS_TRUE(0 == munmap(region, alignment - offset));
 
339
    if (uintptr_t(end) != regionEnd)
 
340
        JS_ALWAYS_TRUE(0 == munmap(end, regionEnd - uintptr_t(end)));
 
341
 
 
342
    JS_ASSERT(uintptr_t(front) % alignment == 0);
 
343
    return front;
 
344
}
 
345
 
 
346
void
 
347
UnmapPages(void *p, size_t size)
 
348
{
 
349
    JS_ALWAYS_TRUE(0 == munmap(p, size));
 
350
}
 
351
 
 
352
bool
 
353
MarkPagesUnused(void *p, size_t size)
 
354
{
 
355
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
356
    int result = madvise(p, size, MADV_DONTNEED);
 
357
    return result != -1;
 
358
}
 
359
 
 
360
bool
 
361
MarkPagesInUse(void *p, size_t size)
 
362
{
 
363
    JS_ASSERT(uintptr_t(p) % PageSize == 0);
 
364
    return true;
 
365
}
 
366
 
 
367
size_t
 
368
GetPageFaultCount()
 
369
{
 
370
    struct rusage usage;
 
371
    int err = getrusage(RUSAGE_SELF, &usage);
 
372
    if (err)
 
373
        return 0;
 
374
    return usage.ru_minflt + usage.ru_majflt;
 
375
}
 
376
 
 
377
#else
 
378
#error "Memory mapping functions are not defined for your OS."
 
379
#endif
 
380
 
 
381
} /* namespace gc */
 
382
} /* namespace js */