mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 553812 - separate GC arena info and mark bits from the arena. r=gal,anygregor
This commit is contained in:
parent
8c46df6c46
commit
91e9546ca9
@ -139,6 +139,7 @@ CPPSRCS = \
|
||||
jsexn.cpp \
|
||||
jsfun.cpp \
|
||||
jsgc.cpp \
|
||||
jsgcchunk.cpp \
|
||||
jshash.cpp \
|
||||
jsinterp.cpp \
|
||||
jsinvoke.cpp \
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -40,6 +40,7 @@
|
||||
#define jsbit_h___
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jscompat.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
@ -47,7 +48,7 @@ JS_BEGIN_EXTERN_C
|
||||
/*
|
||||
** A jsbitmap_t is a long integer that can be used for bitmaps
|
||||
*/
|
||||
typedef JSUword jsbitmap_t; /* NSPR name, a la Unix system types */
|
||||
typedef jsuword jsbitmap_t; /* NSPR name, a la Unix system types */
|
||||
typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */
|
||||
|
||||
#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \
|
||||
@ -251,6 +252,36 @@ extern size_t js_FloorLog2wImpl(size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
inline size_t
|
||||
CountTrailingZeros(size_t n)
|
||||
{
|
||||
JS_ASSERT(n != 0);
|
||||
#if JS_BYTES_PER_WORD != 4 && JS_BYTES_PER_WORD != 8
|
||||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4 && defined JS_HAS_BUILTIN_BITSCAN32
|
||||
return js_bitscan_ctz32(n);
|
||||
#elif JS_BYTES_PER_WORD == 8 && defined JS_HAS_BUILTIN_BITSCAN64
|
||||
return js_bitscan_ctz64(n);
|
||||
#else
|
||||
size_t count = 0;
|
||||
# if JS_BYTES_PER_WORD == 8
|
||||
if (!(n & size_t(0xFFFFFFFFU))) { count += 32; n >>= 32; }
|
||||
# endif
|
||||
if (!(n & 0xFFFF)) { count += 16; n >>= 16; }
|
||||
if (!(n & 0xFF)) { count += 8; n >>= 8; }
|
||||
if (!(n & 0xF)) { count += 4; n >>= 4; }
|
||||
if (!(n & 0x3)) { count += 2; n >>= 2; }
|
||||
if (!(n & 0x1)) { count += 1; n >>= 1; }
|
||||
return count + 1 - (n & 0x1);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for rotate left. There is no rotate operation in the C Language so
|
||||
* the construct (a << 4) | (a >> 28) is used instead. Most compilers convert
|
||||
|
1261
js/src/jsgc.cpp
1261
js/src/jsgc.cpp
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -434,15 +434,19 @@ struct JSGCStats {
|
||||
uint32 maxunmarked;/* maximum number of things with children to mark
|
||||
later */
|
||||
#endif
|
||||
uint32 maxlevel; /* maximum GC nesting (indirect recursion) level */
|
||||
uint32 poke; /* number of potentially useful GC calls */
|
||||
uint32 afree; /* thing arenas freed so far */
|
||||
uint32 stackseg; /* total extraordinary stack segments scanned */
|
||||
uint32 segslots; /* total stack segment jsval slots scanned */
|
||||
uint32 nclose; /* number of objects with close hooks */
|
||||
uint32 maxnclose; /* max number of objects with close hooks */
|
||||
uint32 closelater; /* number of close hooks scheduled to run */
|
||||
uint32 maxcloselater; /* max number of close hooks scheduled to run */
|
||||
uint32 maxlevel; /* maximum GC nesting (indirect recursion) level */
|
||||
uint32 poke; /* number of potentially useful GC calls */
|
||||
uint32 afree; /* thing arenas freed so far */
|
||||
uint32 stackseg; /* total extraordinary stack segments scanned */
|
||||
uint32 segslots; /* total stack segment jsval slots scanned */
|
||||
uint32 nclose; /* number of objects with close hooks */
|
||||
uint32 maxnclose; /* max number of objects with close hooks */
|
||||
uint32 closelater; /* number of close hooks scheduled to run */
|
||||
uint32 maxcloselater; /* max number of close hooks scheduled to run */
|
||||
uint32 nallarenas; /* number of all allocated arenas */
|
||||
uint32 maxnallarenas; /* maximum number of all allocated arenas */
|
||||
uint32 nchunks; /* number of allocated chunks */
|
||||
uint32 maxnchunks; /* maximum number of allocated chunks */
|
||||
|
||||
JSGCArenaStats arenaStats[FINALIZE_LIMIT];
|
||||
JSGCArenaStats doubleArenaStats;
|
||||
|
310
js/src/jsgcchunk.cpp
Normal file
310
js/src/jsgcchunk.cpp
Normal file
@ -0,0 +1,310 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Copyright (C) 2006-2008 Jason Evans <jasone@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer as
|
||||
* the first lines of this file unmodified other than the possible
|
||||
* addition of one or more copyright notices.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "jstypes.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsgcchunk.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include <windows.h>
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning( disable: 4267 4996 4146 )
|
||||
# endif
|
||||
|
||||
#elif defined(XP_MACOSX) || defined(DARWIN)
|
||||
|
||||
# include <libkern/OSAtomic.h>
|
||||
# include <mach/mach_error.h>
|
||||
# include <mach/mach_init.h>
|
||||
# include <mach/vm_map.h>
|
||||
# include <malloc/malloc.h>
|
||||
|
||||
#elif defined(XP_UNIX) || defined(XP_BEOS)
|
||||
|
||||
# include <unistd.h>
|
||||
# include <sys/mman.h>
|
||||
|
||||
# ifndef MAP_NOSYNC
|
||||
# define MAP_NOSYNC 0
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
/*
|
||||
* On Windows CE < 6 we must use separated MEM_RESERVE and MEM_COMMIT
|
||||
* VirtualAlloc calls and we cannot use MEM_RESERVE to allocate at the given
|
||||
* address. So we use a workaround based on oversized allocation.
|
||||
*/
|
||||
# if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
|
||||
|
||||
# define JS_GC_HAS_MAP_ALIGN
|
||||
|
||||
static void
|
||||
UnmapPagesAtBase(void *p)
|
||||
{
|
||||
JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE));
|
||||
}
|
||||
|
||||
static void *
|
||||
MapAlignedPages(size_t size, size_t alignment)
|
||||
{
|
||||
JS_ASSERT(size % alignment == 0);
|
||||
JS_ASSERT(size >= alignment);
|
||||
|
||||
void *reserve = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
|
||||
void *p = VirtualAlloc(reserve, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == reserve);
|
||||
|
||||
size_t mask = alignment - 1;
|
||||
size_t offset = (uintptr_t) p & mask;
|
||||
if (!offset)
|
||||
return p;
|
||||
|
||||
/* Try to extend the initial allocation. */
|
||||
UnmapPagesAtBase(reserve);
|
||||
reserve = VirtualAlloc(NULL, size + alignment - offset, MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
if (offset == ((uintptr_t) reserve & mask)) {
|
||||
void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
|
||||
p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == aligned);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* over allocate to ensure we have an aligned region */
|
||||
UnmapPagesAtBase(reserve);
|
||||
reserve = VirtualAlloc(NULL, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
|
||||
if (!reserve)
|
||||
return NULL;
|
||||
|
||||
offset = (uintptr_t) reserve & mask;
|
||||
void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
|
||||
p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
JS_ASSERT(p == aligned);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
UnmapPages(void *p, size_t size)
|
||||
{
|
||||
if (VirtualFree(p, 0, MEM_RELEASE))
|
||||
return;
|
||||
|
||||
/* We could have used the over allocation. */
|
||||
JS_ASSERT(GetLastError() == ERROR_INVALID_PARAMETER);
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
VirtualQuery(p, &info, sizeof(info));
|
||||
|
||||
UnmapPagesAtBase(info.AllocationBase);
|
||||
}
|
||||
|
||||
# else /* WINCE */
|
||||
|
||||
static void *
|
||||
MapPages(void *addr, size_t size)
|
||||
{
|
||||
void *p = VirtualAlloc(addr, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
||||
JS_ASSERT_IF(p && addr, p == addr);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
UnmapPages(void *addr, size_t size)
|
||||
{
|
||||
JS_ALWAYS_TRUE(VirtualFree(addr, 0, MEM_RELEASE));
|
||||
}
|
||||
|
||||
# endif /* !WINCE */
|
||||
|
||||
#elif defined(XP_MACOSX) || defined(DARWIN)
|
||||
|
||||
static void *
|
||||
MapPages(void *addr, size_t size)
|
||||
{
|
||||
void *p;
|
||||
int flags;
|
||||
if (addr) {
|
||||
p = addr;
|
||||
flags = 0;
|
||||
} else {
|
||||
flags = VM_FLAGS_ANYWHERE;
|
||||
}
|
||||
|
||||
kern_return_t err = vm_allocate((vm_map_t) mach_task_self(),
|
||||
(vm_address_t *) &p,
|
||||
(vm_size_t) size, flags);
|
||||
if (err != KERN_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(p);
|
||||
JS_ASSERT_IF(addr, p == addr);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
UnmapPages(void *addr, size_t size)
|
||||
{
|
||||
JS_ALWAYS_TRUE(vm_deallocate((vm_map_t) mach_task_self(),
|
||||
(vm_address_t) addr,
|
||||
(vm_size_t) size)
|
||||
== KERN_SUCCESS);
|
||||
}
|
||||
|
||||
#elif defined(XP_UNIX) || defined(XP_BEOS)
|
||||
|
||||
/* Required on Solaris 10. Might improve performance elsewhere. */
|
||||
# if defined(SOLARIS) && defined(MAP_ALIGN)
|
||||
# define JS_GC_HAS_MAP_ALIGN
|
||||
|
||||
static void *
|
||||
MapAlignedPages(size_t size, size_t alignment)
|
||||
{
|
||||
/*
|
||||
* We don't use MAP_FIXED here, because it can cause the *replacement*
|
||||
* of existing mappings, and we only want to create new mappings.
|
||||
*/
|
||||
void *p = mmap((void *) alignment, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_NOSYNC | MAP_ALIGN | MAP_ANON, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
# else /* JS_GC_HAS_MAP_ALIGN */
|
||||
|
||||
static void *
|
||||
MapPages(void *addr, size_t size)
|
||||
{
|
||||
/*
|
||||
* We don't use MAP_FIXED here, because it can cause the *replacement*
|
||||
* of existing mappings, and we only want to create new mappings.
|
||||
*/
|
||||
void *p = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
|
||||
-1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return NULL;
|
||||
if (addr && p != addr) {
|
||||
/* We succeeded in mapping memory, but not in the right place. */
|
||||
JS_ALWAYS_TRUE(munmap(p, size) == 0);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
# endif /* !JS_GC_HAS_MAP_ALIGN */
|
||||
|
||||
static void
|
||||
UnmapPages(void *addr, size_t size)
|
||||
{
|
||||
JS_ALWAYS_TRUE(munmap(addr, size) == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
inline void *
|
||||
FindChunkStart(void *p)
|
||||
{
|
||||
jsuword addr = reinterpret_cast<jsuword>(p);
|
||||
addr = (addr + GC_CHUNK_MASK) & ~GC_CHUNK_MASK;
|
||||
return reinterpret_cast<void *>(addr);
|
||||
}
|
||||
|
||||
void *
|
||||
AllocGCChunk()
|
||||
{
|
||||
void *p;
|
||||
|
||||
#if JS_GC_HAS_MAP_ALIGN
|
||||
p = MapAlignedPages(GC_CHUNK_SIZE, GC_CHUNK_SIZE);
|
||||
if (!p)
|
||||
return NULL;
|
||||
#else
|
||||
/*
|
||||
* Windows requires that there be a 1:1 mapping between VM allocation
|
||||
* and deallocation operations. Therefore, take care here to acquire the
|
||||
* final result via one mapping operation. This means unmapping any
|
||||
* preliminary result that is not correctly aligned.
|
||||
*/
|
||||
p = MapPages(NULL, GC_CHUNK_SIZE);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (reinterpret_cast<jsuword>(p) & GC_CHUNK_MASK) {
|
||||
UnmapPages(p, GC_CHUNK_SIZE);
|
||||
p = MapPages(FindChunkStart(p), GC_CHUNK_SIZE);
|
||||
while (!p) {
|
||||
/*
|
||||
* Over-allocate in order to map a memory region that is
|
||||
* definitely large enough then deallocate and allocate again the
|
||||
* correct size, within the over-sized mapping.
|
||||
*/
|
||||
p = MapPages(NULL, GC_CHUNK_SIZE * 2);
|
||||
if (!p)
|
||||
return 0;
|
||||
UnmapPages(p, GC_CHUNK_SIZE * 2);
|
||||
p = MapPages(FindChunkStart(p), GC_CHUNK_SIZE);
|
||||
|
||||
/*
|
||||
* Failure here indicates a race with another thread, so
|
||||
* try again.
|
||||
*/
|
||||
}
|
||||
}
|
||||
#endif /* !JS_GC_HAS_MAP_ALIGN */
|
||||
|
||||
JS_ASSERT(!(reinterpret_cast<jsuword>(p) & GC_CHUNK_MASK));
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
FreeGCChunk(void *p)
|
||||
{
|
||||
JS_ASSERT(p);
|
||||
JS_ASSERT(!(reinterpret_cast<jsuword>(p) & GC_CHUNK_MASK));
|
||||
UnmapPages(p, GC_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
66
js/src/jsgcchunk.h
Normal file
66
js/src/jsgcchunk.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9.1 code, released
|
||||
* June 30, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov <igor@mir2.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsgchunk_h__
|
||||
#define jsgchunk_h__
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
#if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
|
||||
const size_t GC_CHUNK_SHIFT = 21;
|
||||
#else
|
||||
const size_t GC_CHUNK_SHIFT = 20;
|
||||
#endif
|
||||
|
||||
const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT;
|
||||
const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1;
|
||||
|
||||
void *
|
||||
AllocGCChunk();
|
||||
|
||||
void
|
||||
FreeGCChunk(void *p);
|
||||
|
||||
}
|
||||
|
||||
#endif /* jsgchunk_h__ */
|
Loading…
Reference in New Issue
Block a user