Bug 684039: rewrite JS LIFO allocator, avoids thrashing. (r=luke)

--HG--
rename : js/src/jsarena.h => js/src/ds/LifoAlloc.h
This commit is contained in:
Chris Leary 2011-09-22 13:22:30 -07:00
parent caf928aafd
commit b7a2ff75e7
43 changed files with 726 additions and 945 deletions

View File

@ -59,7 +59,6 @@
#include "nsDOMError.h"
#include "nsDOMCID.h"
#include "jsdbgapi.h"
#include "jsarena.h"
#include "jsfun.h"
#include "jsobj.h"
#include "nsIXPConnect.h"

View File

@ -101,7 +101,6 @@ CPPSRCS = \
jsalloc.cpp \
jsanalyze.cpp \
jsapi.cpp \
jsarena.cpp \
jsarray.cpp \
jsatom.cpp \
jsbool.cpp \
@ -161,6 +160,7 @@ CPPSRCS = \
Stack.cpp \
String.cpp \
ParseMaps.cpp \
LifoAlloc.cpp \
Unicode.cpp \
$(NULL)
@ -174,7 +174,6 @@ INSTALLED_HEADERS = \
js.msg \
jsalloc.h \
jsapi.h \
jsarena.h \
jsatom.h \
jsbit.h \
jsclass.h \
@ -241,9 +240,10 @@ INSTALLED_HEADERS = \
VPATH += \
$(srcdir)/vm \
$(srcdir)/frontend \
$(srcdir)/ds \
$(NULL)
EXPORTS_NAMESPACES = vm
EXPORTS_NAMESPACES = vm ds
EXPORTS_vm = \
ArgumentsObject.h \
@ -255,6 +255,9 @@ EXPORTS_vm = \
Unicode.h \
$(NULL)
EXPORTS_ds = \
LifoAlloc.h
###############################################
# BEGIN include sources for low-level code shared with Gecko
#

149
js/src/ds/LifoAlloc.cpp Normal file
View File

@ -0,0 +1,149 @@
#include "LifoAlloc.h"
#include <new>
using namespace js;
namespace js {
namespace detail {
BumpChunk *
BumpChunk::new_(size_t chunkSize)
{
JS_ASSERT(RoundUpPow2(chunkSize) == chunkSize);
void *mem = js_malloc(chunkSize);
if (!mem)
return NULL;
BumpChunk *result = new (mem) BumpChunk(chunkSize - sizeof(BumpChunk));
/*
* We assume that the alignment of sAlign is less than that of
* the underlying memory allocator -- creating a new BumpChunk should
* always satisfy the sAlign alignment constraint.
*/
JS_ASSERT(AlignPtr(result->bump) == result->bump);
return result;
}
void *
BumpChunk::tryAllocUnaligned(size_t n)
{
char *oldBump = bump;
char *newBump = bump + n;
if (newBump > limit)
return NULL;
setBump(newBump);
return oldBump;
}
} /* namespace detail */
} /* namespace js */
void
LifoAlloc::freeAll()
{
while (first) {
BumpChunk *victim = first;
first = first->next();
BumpChunk::delete_(victim);
}
first = latest = NULL;
}
void
LifoAlloc::freeUnused()
{
/* Don't free anything if we have outstanding marks. */
if (markCount || !first)
return;
JS_ASSERT(first && latest);
/* Rewind through any unused chunks. */
if (!latest->used()) {
BumpChunk *lastUsed = NULL;
for (BumpChunk *it = first; it != latest; it = it->next()) {
if (it->used())
lastUsed = it;
}
if (!lastUsed) {
freeAll();
return;
}
latest = lastUsed;
}
/* Free all chunks after |latest|. */
size_t freed = 0;
for (BumpChunk *victim = latest->next(); victim; victim = victim->next()) {
BumpChunk::delete_(victim);
freed++;
}
}
LifoAlloc::BumpChunk *
LifoAlloc::getOrCreateChunk(size_t n)
{
if (first) {
/* Look for existing, unused BumpChunks to satisfy the request. */
while (latest->next()) {
latest = latest->next();
latest->resetBump(); /* This was an unused BumpChunk on the chain. */
if (latest->canAlloc(n))
return latest;
}
}
size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk);
size_t chunkSize = n > defaultChunkFreeSpace
? RoundUpPow2(n + sizeof(BumpChunk))
: defaultChunkSize_;
/* If we get here, we couldn't find an existing BumpChunk to fill the request. */
BumpChunk *newChunk = BumpChunk::new_(chunkSize);
if (!newChunk)
return NULL;
if (!first) {
latest = first = newChunk;
} else {
JS_ASSERT(latest && !latest->next());
latest->setNext(newChunk);
latest = newChunk;
}
return newChunk;
}
void *
LifoAlloc::allocUnaligned(size_t n)
{
void *result;
if (latest && (result = latest->tryAllocUnaligned(n)))
return result;
return alloc(n);
}
void *
LifoAlloc::reallocUnaligned(void *origPtr, size_t origSize, size_t incr)
{
JS_ASSERT(first && latest);
/*
* Maybe we can grow the latest allocation in a BumpChunk.
*
* Note: we could also realloc the whole BumpChunk in the !canAlloc
* case, but this should not be a frequently hit case.
*/
if (latest
&& origPtr == (char *) latest->mark() - origSize
&& latest->canAllocUnaligned(incr)) {
JS_ALWAYS_TRUE(allocUnaligned(incr));
return origPtr;
}
/* Otherwise, memcpy. */
size_t newSize = origSize + incr;
void *newPtr = allocUnaligned(newSize);
return newPtr ? memcpy(newPtr, origPtr, origSize) : NULL;
}

339
js/src/ds/LifoAlloc.h Normal file
View File

@ -0,0 +1,339 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 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 code, released
* June 12, 2009.
*
* The Initial Developer of the Original Code is
* the Mozilla Corporation.
*
* Contributor(s):
* Chris Leary <cdleary@mozilla.com>
*
* 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 LifoAlloc_h__
#define LifoAlloc_h__
/*
* Lifetime-based fast allocation, inspired by much prior art, including
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
*
* This data structure supports stacky LIFO allocation (mark/release and
* LifoAllocScope). It does not maintain one contiguous segment; instead, it
* maintains a bunch of linked memory segments. In order to prevent malloc/free
* thrashing, unused segments are deallocated when garbage collection occurs.
*/
#include "jsutil.h"
#include "jstl.h"
namespace js {
namespace detail {
static const size_t LIFO_ALLOC_ALIGN = 8;
JS_ALWAYS_INLINE
char *
AlignPtr(void *orig)
{
typedef typename tl::StaticAssert<
tl::FloorLog2<LIFO_ALLOC_ALIGN>::result == tl::CeilingLog2<LIFO_ALLOC_ALIGN>::result
>::result _;
char *result = (char *) ((uintptr_t(orig) + (LIFO_ALLOC_ALIGN - 1)) & -LIFO_ALLOC_ALIGN);
JS_ASSERT(uintptr_t(result) % LIFO_ALLOC_ALIGN == 0);
return result;
}
/* Header for a chunk of memory wrangled by the LifoAlloc. */
class BumpChunk
{
char *bump;
char *limit;
BumpChunk *next_;
size_t bumpSpaceSize;
char *base() const { return limit - bumpSpaceSize; }
explicit BumpChunk(size_t bumpSpaceSize)
: bump(reinterpret_cast<char *>(this) + sizeof(BumpChunk)), limit(bump + bumpSpaceSize),
next_(NULL), bumpSpaceSize(bumpSpaceSize) {
JS_ASSERT(bump == AlignPtr(bump));
}
void clobberUnused() {
#ifdef DEBUG
memset(bump, 0xcd, limit - bump);
#endif
}
void setBump(void *ptr) {
JS_ASSERT(base() <= ptr);
JS_ASSERT(ptr <= limit);
DebugOnly<char *> prevBump = bump;
bump = static_cast<char *>(ptr);
if (prevBump < bump)
clobberUnused();
}
public:
BumpChunk *next() const { return next_; }
void setNext(BumpChunk *succ) { next_ = succ; }
size_t used() const { return bump - base(); }
void resetBump() {
setBump(reinterpret_cast<char *>(this) + sizeof(BumpChunk));
}
void *mark() const { return bump; }
void release(void *mark) {
JS_ASSERT(contains(mark));
JS_ASSERT(mark <= bump);
setBump(mark);
}
bool contains(void *mark) const {
return base() <= mark && mark <= limit;
}
bool canAlloc(size_t n) {
return AlignPtr(bump) + n <= limit;
}
bool canAllocUnaligned(size_t n) {
return bump + n <= limit;
}
/* Try to perform an allocation of size |n|, return null if not possible. */
JS_ALWAYS_INLINE
void *tryAlloc(size_t n) {
char *aligned = AlignPtr(bump);
char *newBump = aligned + n;
if (newBump > limit)
return NULL;
setBump(newBump);
return aligned;
}
void *tryAllocUnaligned(size_t n);
void *allocInfallible(size_t n) {
void *result = tryAlloc(n);
JS_ASSERT(result);
return result;
}
static BumpChunk *new_(size_t chunkSize);
static void delete_(BumpChunk *chunk) {
#ifdef DEBUG
memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize);
#endif
js_free(chunk);
}
};
} /* namespace detail */
/*
* LIFO bump allocator: used for phase-oriented and fast LIFO allocations.
*
* Note: |latest| is not necessary "last". We leave BumpChunks latent in the
* chain after they've been released to avoid thrashing before a GC.
*/
class LifoAlloc
{
typedef detail::BumpChunk BumpChunk;
BumpChunk *first;
BumpChunk *latest;
size_t markCount;
size_t defaultChunkSize_;
void operator=(const LifoAlloc &);
LifoAlloc(const LifoAlloc &);
/*
* Return a BumpChunk that can perform an allocation of at least size |n|
* and add it to the chain appropriately.
*
* Side effect: if retval is non-null, |first| and |latest| are initialized
* appropriately.
*/
BumpChunk *getOrCreateChunk(size_t n);
void reset(size_t defaultChunkSize) {
JS_ASSERT(RoundUpPow2(defaultChunkSize) == defaultChunkSize);
first = latest = NULL;
defaultChunkSize_ = defaultChunkSize;
markCount = 0;
}
public:
explicit LifoAlloc(size_t defaultChunkSize) { reset(defaultChunkSize); }
/* Steal allocated chunks from |other|. */
void steal(LifoAlloc *other) {
JS_ASSERT(!other->markCount);
PodCopy((char *) this, (char *) other, sizeof(*this));
other->reset(defaultChunkSize_);
}
~LifoAlloc() { freeAll(); }
size_t defaultChunkSize() const { return defaultChunkSize_; }
/* Frees all held memory. */
void freeAll();
/* Should be called on GC in order to release any held chunks. */
void freeUnused();
JS_ALWAYS_INLINE
void *alloc(size_t n) {
void *result;
if (latest && (result = latest->tryAlloc(n)))
return result;
if (!getOrCreateChunk(n))
return NULL;
return latest->allocInfallible(n);
}
template <typename T>
T *newArray(size_t count) {
void *mem = alloc(sizeof(T) * count);
if (!mem)
return NULL;
JS_STATIC_ASSERT(tl::IsPodType<T>::result);
return (T *) mem;
}
/*
* Create an array with uninitialized elements of type |T|.
* The caller is responsible for initialization.
*/
template <typename T>
T *newArrayUninitialized(size_t count) {
return static_cast<T *>(alloc(sizeof(T) * count));
}
void *mark() {
markCount++;
return latest ? latest->mark() : NULL;
}
void release(void *mark) {
markCount--;
if (!mark) {
latest = first;
if (latest)
latest->resetBump();
return;
}
/*
* Find the chunk that contains |mark|, and make sure we don't pass
* |latest| along the way -- we should be making the chain of active
* chunks shorter, not longer!
*/
BumpChunk *container = first;
while (true) {
if (container->contains(mark))
break;
JS_ASSERT(container != latest);
container = container->next();
}
latest = container;
latest->release(mark);
}
/* Get the total "used" (occupied bytes) count for the arena chunks. */
size_t used() const {
size_t accum = 0;
BumpChunk *it = first;
while (it) {
accum += it->used();
it = it->next();
}
return accum;
}
/* Doesn't perform construction; useful for lazily-initialized POD types. */
template <typename T>
JS_ALWAYS_INLINE
T *newPod() {
return static_cast<T *>(alloc(sizeof(T)));
}
JS_DECLARE_NEW_METHODS(alloc, JS_ALWAYS_INLINE)
/* Some legacy clients (ab)use LifoAlloc to act like a vector, see bug 688891. */
void *allocUnaligned(size_t n);
void *reallocUnaligned(void *origPtr, size_t origSize, size_t incr);
};
class LifoAllocScope {
LifoAlloc *lifoAlloc;
void *mark;
bool shouldRelease;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
explicit LifoAllocScope(LifoAlloc *lifoAlloc
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: lifoAlloc(lifoAlloc), shouldRelease(true) {
JS_GUARD_OBJECT_NOTIFIER_INIT;
mark = lifoAlloc->mark();
}
~LifoAllocScope() {
if (shouldRelease)
lifoAlloc->release(mark);
}
void releaseEarly() {
JS_ASSERT(shouldRelease);
lifoAlloc->release(mark);
shouldRelease = false;
}
};
} /* namespace js */
#endif

View File

@ -39,6 +39,7 @@
* ***** END LICENSE BLOCK ***** */
#include "ParseMaps-inl.h"
#include "jscompartment.h"
using namespace js;
@ -125,13 +126,12 @@ DumpAtomDefnMap(const AtomDefnMapPtr &map)
AtomDeclNode *
AtomDecls::allocNode(JSDefinition *defn)
{
AtomDeclNode *p;
JS_ARENA_ALLOCATE_TYPE(p, AtomDeclNode, &cx->tempPool);
AtomDeclNode *p = cx->tempLifoAlloc().new_<AtomDeclNode>(defn);
if (!p) {
js_ReportOutOfMemory(cx);
return NULL;
}
return new (p) AtomDeclNode(defn);
return p;
}
bool

View File

@ -109,8 +109,7 @@ Bytecode::mergeDefines(JSContext *cx, ScriptAnalysis *script, bool initial,
* with progressively smaller sets of defined variables.
*/
if (!owned) {
uint32 *reallocArray =
ArenaArray<uint32>(cx->compartment->pool, defineCount);
uint32 *reallocArray = cx->typeLifoAlloc().newArray<uint32>(defineCount);
if (!reallocArray) {
script->setOOM(cx);
return false;
@ -134,12 +133,11 @@ void
PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc)
{
printf("#%u:", script->id());
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAlloc lifoAlloc(1024);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
js_Disassemble1(cx, script, pc, pc - script->code, true, &sprinter);
fprintf(stdout, "%s", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
}
#endif
@ -157,7 +155,7 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
Bytecode *&code = codeArray[offset];
bool initial = (code == NULL);
if (initial) {
code = ArenaNew<Bytecode>(cx->compartment->pool);
code = cx->typeLifoAlloc().new_<Bytecode>();
if (!code) {
setOOM(cx);
return false;
@ -278,16 +276,16 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
{
JS_ASSERT(cx->compartment->activeAnalysis);
JS_ASSERT(!ranBytecode());
JSArenaPool &pool = cx->compartment->pool;
LifoAlloc &tla = cx->typeLifoAlloc();
unsigned length = script->length;
unsigned nargs = script->hasFunction ? script->function()->nargs : 0;
numSlots = TotalSlots(script);
codeArray = ArenaArray<Bytecode*>(pool, length);
definedLocals = ArenaArray<uint32>(pool, script->nfixed);
escapedSlots = ArenaArray<JSPackedBool>(pool, numSlots);
codeArray = tla.newArray<Bytecode*>(length);
definedLocals = tla.newArray<uint32>(script->nfixed);
escapedSlots = tla.newArray<JSPackedBool>(numSlots);
if (!codeArray || !definedLocals || !escapedSlots) {
setOOM(cx);
@ -371,7 +369,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
unsigned forwardCatch = 0;
/* Fill in stack depth and definitions at initial bytecode. */
Bytecode *startcode = ArenaNew<Bytecode>(pool);
Bytecode *startcode = tla.new_<Bytecode>();
if (!startcode) {
setOOM(cx);
return;
@ -703,7 +701,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
if (definedLocals[local] == LOCAL_CONDITIONALLY_DEFINED) {
if (forwardJump) {
/* Add this local to the variables defined after this bytecode. */
uint32 *newArray = ArenaArray<uint32>(pool, defineCount + 1);
uint32 *newArray = tla.newArray<uint32>(defineCount + 1);
if (!newArray) {
setOOM(cx);
return;
@ -795,7 +793,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
bool initial = (nextcode == NULL);
if (initial) {
nextcode = ArenaNew<Bytecode>(pool);
nextcode = tla.new_<Bytecode>();
if (!nextcode) {
setOOM(cx);
return;
@ -839,9 +837,9 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
return;
}
JSArenaPool &pool = cx->compartment->pool;
LifoAlloc &tla = cx->typeLifoAlloc();
lifetimes = ArenaArray<LifetimeVariable>(pool, numSlots);
lifetimes = tla.newArray<LifetimeVariable>(numSlots);
if (!lifetimes) {
setOOM(cx);
return;
@ -969,7 +967,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
/* Restore all saved variables. :FIXME: maybe do this precisely. */
for (unsigned i = 0; i < savedCount; i++) {
LifetimeVariable &var = *saved[i];
var.lifetime = ArenaNew<Lifetime>(pool, offset, var.savedEnd, var.saved);
var.lifetime = tla.new_<Lifetime>(offset, var.savedEnd, var.saved);
if (!var.lifetime) {
cx->free_(saved);
setOOM(cx);
@ -1036,7 +1034,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (loop && loop->entry > loop->lastBlock)
loop->lastBlock = loop->entry;
LoopAnalysis *nloop = ArenaNew<LoopAnalysis>(pool);
LoopAnalysis *nloop = tla.new_<LoopAnalysis>();
if (!nloop) {
cx->free_(saved);
setOOM(cx);
@ -1085,7 +1083,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
* Jumping to a place where this variable is live. Make a new
* lifetime segment for the variable.
*/
var.lifetime = ArenaNew<Lifetime>(pool, offset, var.savedEnd, var.saved);
var.lifetime = tla.new_<Lifetime>(offset, var.savedEnd, var.saved);
if (!var.lifetime) {
cx->free_(saved);
setOOM(cx);
@ -1149,7 +1147,7 @@ ScriptAnalysis::addVariable(JSContext *cx, LifetimeVariable &var, unsigned offse
}
}
}
var.lifetime = ArenaNew<Lifetime>(cx->compartment->pool, offset, var.savedEnd, var.saved);
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
if (!var.lifetime) {
setOOM(cx);
return;
@ -1166,7 +1164,7 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
/* Make a point lifetime indicating the write. */
if (!var.saved)
saved[savedCount++] = &var;
var.saved = ArenaNew<Lifetime>(cx->compartment->pool, offset, var.savedEnd, var.saved);
var.saved = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
if (!var.saved) {
setOOM(cx);
return;
@ -1252,7 +1250,7 @@ ScriptAnalysis::extendVariable(JSContext *cx, LifetimeVariable &var,
}
JS_ASSERT(savedEnd <= end);
if (savedEnd > segment->end) {
Lifetime *tail = ArenaNew<Lifetime>(cx->compartment->pool, savedEnd, 0, segment->next);
Lifetime *tail = cx->typeLifoAlloc().new_<Lifetime>(savedEnd, 0, segment->next);
if (!tail) {
setOOM(cx);
return;
@ -1329,7 +1327,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
return;
}
JSArenaPool &pool = cx->compartment->pool;
LifoAlloc &tla = cx->typeLifoAlloc();
unsigned maxDepth = script->nslots - script->nfixed;
/*
@ -1490,7 +1488,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
if (xuses) {
code->poppedValues = (SSAValue *)ArenaArray<SSAValue>(pool, xuses);
code->poppedValues = tla.newArray<SSAValue>(xuses);
if (!code->poppedValues) {
setOOM(cx);
return;
@ -1513,7 +1511,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
}
if (xuses) {
SSAUseChain *useChains = ArenaArray<SSAUseChain>(cx->compartment->pool, xuses);
SSAUseChain *useChains = tla.newArray<SSAUseChain>(xuses);
if (!useChains) {
setOOM(cx);
return;
@ -1540,7 +1538,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
unsigned xdefs = ExtendedDef(pc) ? ndefs + 1 : ndefs;
if (xdefs) {
code->pushedUses = ArenaArray<SSAUseChain *>(cx->compartment->pool, xdefs);
code->pushedUses = tla.newArray<SSAUseChain *>(xdefs);
if (!code->pushedUses) {
setOOM(cx);
return;
@ -1731,8 +1729,8 @@ PhiNodeCapacity(unsigned length)
bool
ScriptAnalysis::makePhi(JSContext *cx, uint32 slot, uint32 offset, SSAValue *pv)
{
SSAPhiNode *node = ArenaNew<SSAPhiNode>(cx->compartment->pool);
SSAValue *options = ArenaArray<SSAValue>(cx->compartment->pool, PhiNodeCapacity(0));
SSAPhiNode *node = cx->typeLifoAlloc().new_<SSAPhiNode>();
SSAValue *options = cx->typeLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(0));
if (!node || !options) {
setOOM(cx);
return false;
@ -1764,7 +1762,7 @@ ScriptAnalysis::insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v)
if (trackUseChain(v)) {
SSAUseChain *&uses = useChain(v);
SSAUseChain *use = ArenaNew<SSAUseChain>(cx->compartment->pool);
SSAUseChain *use = cx->typeLifoAlloc().new_<SSAUseChain>();
if (!use) {
setOOM(cx);
return;
@ -1782,8 +1780,8 @@ ScriptAnalysis::insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v)
return;
}
SSAValue *newOptions = ArenaArray<SSAValue>(cx->compartment->pool,
PhiNodeCapacity(node->length + 1));
SSAValue *newOptions =
cx->typeLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(node->length + 1));
if (!newOptions) {
setOOM(cx);
return;
@ -1922,7 +1920,7 @@ ScriptAnalysis::freezeNewValues(JSContext *cx, uint32 offset)
return;
}
code.newValues = ArenaArray<SlotValue>(cx->compartment->pool, count + 1);
code.newValues = cx->typeLifoAlloc().newArray<SlotValue>(count + 1);
if (!code.newValues) {
setOOM(cx);
return;

View File

@ -41,11 +41,13 @@
#ifndef jsanalyze_h___
#define jsanalyze_h___
#include "jsarena.h"
#include "jscompartment.h"
#include "jscntxt.h"
#include "jsinfer.h"
#include "jsscript.h"
#include "jstl.h"
#include "ds/LifoAlloc.h"
struct JSScript;
@ -83,11 +85,6 @@ namespace analyze {
* analyses are independent from type inference.
*/
class SSAValue;
struct SSAUseChain;
struct LoopAnalysis;
struct SlotValue;
/* Information about a bytecode instruction. */
class Bytecode
{
@ -1372,4 +1369,16 @@ void PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc);
} /* namespace analyze */
} /* namespace js */
namespace js {
namespace tl {
template <> struct IsPodType<js::analyze::LifetimeVariable> { static const bool result = true; };
template <> struct IsPodType<js::analyze::LoopAnalysis> { static const bool result = true; };
template <> struct IsPodType<js::analyze::SlotValue> { static const bool result = true; };
template <> struct IsPodType<js::analyze::SSAValue> { static const bool result = true; };
template <> struct IsPodType<js::analyze::SSAUseChain> { static const bool result = true; };
} /* namespace tl */
} /* namespace js */
#endif // jsanalyze_h___

View File

@ -48,7 +48,6 @@
#include <sys/stat.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsclist.h"
#include "jsdhash.h"
@ -100,6 +99,7 @@
#include "vm/Stack-inl.h"
#include "vm/String-inl.h"
#include "ds/LifoAlloc.h"
#if ENABLE_YARR_JIT
#include "assembler/jit/ExecutableAllocator.h"
@ -2608,10 +2608,6 @@ JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
LeaveTrace(cx);
/* Don't nuke active arenas if executing or compiling. */
if (cx->tempPool.current == &cx->tempPool.first)
JS_FinishArenaPool(&cx->tempPool);
GCREASON(PUBLIC_API);
js_GC(cx, comp, GC_NORMAL);
}
@ -2628,10 +2624,6 @@ JS_MaybeGC(JSContext *cx)
{
LeaveTrace(cx);
/* Don't nuke active arenas if executing or compiling. */
if (cx->tempPool.current == &cx->tempPool.first)
JS_FinishArenaPool(&cx->tempPool);
MaybeGC(cx);
}

View File

@ -1,258 +0,0 @@
/* -*- 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
*
* 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 Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
/*
* Lifetime-based fast allocation, inspired by much prior art, including
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
*/
#include <stdlib.h>
#include <string.h>
#include "jsalloc.h"
#include "jstypes.h"
#include "jsstdint.h"
#include "jsbit.h"
#include "jsarena.h"
#include "jsprvtd.h"
using namespace js;
/* If JSArena's length is a multiple of 8, that ensures its payload is 8-aligned. */
JS_STATIC_ASSERT(sizeof(JSArena) % 8 == 0);
JS_PUBLIC_API(void)
JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align)
{
/* Restricting ourselves to some simple alignments keeps things simple. */
if (align == 1 || align == 2 || align == 4 || align == 8) {
pool->mask = align - 1;
} else {
/* This shouldn't happen, but set pool->mask reasonably if it does. */
JS_NOT_REACHED("JS_InitArenaPool: bad align");
pool->mask = 7;
}
pool->first.next = NULL;
/* pool->first is a zero-sized dummy arena that's never allocated from. */
pool->first.base = pool->first.avail = pool->first.limit =
JS_ARENA_ALIGN(pool, &pool->first + 1);
pool->current = &pool->first;
pool->arenasize = size;
}
JS_PUBLIC_API(void *)
JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
{
/*
* Search pool from current forward till we find or make enough space.
*
* NB: subtract nb from a->limit in the loop condition, instead of adding
* nb to a->avail, to avoid overflow (possible when running a 32-bit
* program on a 64-bit system where the kernel maps the heap up against the
* top of the 32-bit address space, see bug 279273). Note that this
* necessitates a comparison between nb and a->limit that looks like a
* (conceptual) type error but isn't.
*/
JS_ASSERT((nb & pool->mask) == 0);
JSArena *a;
/*
* Comparing nb to a->limit looks like a (conceptual) type error, but it's
* necessary to avoid wrap-around. Yuk.
*/
for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; pool->current = a) {
JSArena **ap = &a->next;
if (!*ap) {
/* Not enough space in pool, so we must malloc. */
size_t gross = sizeof(JSArena) + JS_MAX(nb, pool->arenasize);
a = (JSArena *) OffTheBooks::malloc_(gross);
if (!a)
return NULL;
a->next = NULL;
a->base = a->avail = jsuword(a) + sizeof(JSArena);
/*
* Because malloc returns 8-aligned pointers and sizeof(JSArena) is
* a multiple of 8, a->base will always be 8-aligned, which should
* suffice for any valid pool.
*/
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
a->limit = (jsuword)a + gross;
*ap = a;
continue;
}
a = *ap; /* move to next arena */
}
void* p = (void *)a->avail;
a->avail += nb;
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
return p;
}
JS_PUBLIC_API(void *)
JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
{
/* If we've called JS_ArenaRealloc, the new size must be bigger than pool->arenasize. */
JS_ASSERT(size + incr > pool->arenasize);
/* Find the arena containing |p|. */
JSArena *a;
JSArena **ap = &pool->first.next;
while (true) {
a = *ap;
if (JS_IS_IN_ARENA(a, p))
break;
JS_ASSERT(a != pool->current);
ap = &a->next;
}
/* If we've called JS_ArenaRealloc, p must be at the start of an arena. */
JS_ASSERT(a->base == jsuword(p));
size_t gross = sizeof(JSArena) + JS_ARENA_ALIGN(pool, size + incr);
a = (JSArena *) OffTheBooks::realloc_(a, gross);
if (!a)
return NULL;
a->base = jsuword(a) + sizeof(JSArena);
a->avail = a->limit = jsuword(a) + gross;
/*
* Because realloc returns 8-aligned pointers and sizeof(JSArena) is a
* multiple of 8, a->base will always be 8-aligned, which should suffice
* for any valid pool.
*/
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
if (a != *ap) {
/* realloc moved the allocation: update other pointers to a. */
if (pool->current == *ap)
pool->current = a;
*ap = a;
}
return (void *)a->base;
}
JS_PUBLIC_API(void *)
JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr)
{
void *newp;
/*
* If p points to an oversized allocation, it owns an entire arena, so we
* can simply realloc the arena.
*/
if (size > pool->arenasize)
return JS_ArenaRealloc(pool, p, size, incr);
JS_ARENA_ALLOCATE(newp, pool, size + incr);
if (newp)
memcpy(newp, p, size);
return newp;
}
/*
* Free tail arenas linked after head, which may not be the true list head.
* Reset pool->current to point to head in case it pointed at a tail arena.
*/
static void
FreeArenaList(JSArenaPool *pool, JSArena *head)
{
JSArena **ap, *a;
ap = &head->next;
a = *ap;
if (!a)
return;
#ifdef DEBUG
do {
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
a->avail = a->base;
JS_CLEAR_UNUSED(a);
} while ((a = a->next) != NULL);
a = *ap;
#endif
do {
*ap = a->next;
JS_CLEAR_ARENA(a);
UnwantedForeground::free_(a);
} while ((a = *ap) != NULL);
pool->current = head;
}
JS_PUBLIC_API(void)
JS_ArenaRelease(JSArenaPool *pool, char *mark)
{
JSArena *a;
for (a = &pool->first; a; a = a->next) {
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
if (JS_IS_IN_ARENA(a, mark)) {
a->avail = JS_ARENA_ALIGN(pool, mark);
JS_ASSERT(a->avail <= a->limit);
FreeArenaList(pool, a);
return;
}
}
}
JS_PUBLIC_API(void)
JS_FreeArenaPool(JSArenaPool *pool)
{
FreeArenaList(pool, &pool->first);
}
JS_PUBLIC_API(void)
JS_FinishArenaPool(JSArenaPool *pool)
{
FreeArenaList(pool, &pool->first);
}
JS_PUBLIC_API(void)
JS_ArenaFinish()
{
}
JS_PUBLIC_API(void)
JS_ArenaShutDown(void)
{
}

View File

@ -1,317 +0,0 @@
/* -*- 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
*
* 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 Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 jsarena_h___
#define jsarena_h___
/*
* Lifetime-based fast allocation, inspired by much prior art, including
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
*
* Also supports LIFO allocation (JS_ARENA_MARK/JS_ARENA_RELEASE).
*/
#include <stdlib.h>
#include "jstypes.h"
#include "jscompat.h"
#include "jsstaticcheck.h"
JS_BEGIN_EXTERN_C
typedef struct JSArena JSArena;
typedef struct JSArenaPool JSArenaPool;
struct JSArena {
JSArena *next; /* next arena for this lifetime */
jsuword base; /* aligned base address, follows this header */
jsuword limit; /* one beyond last byte in arena */
jsuword avail; /* points to next available byte */
};
struct JSArenaPool {
JSArena first; /* first arena in pool list */
JSArena *current; /* arena from which to allocate space */
size_t arenasize; /* net exact size of a new arena */
jsuword mask; /* alignment mask (power-of-2 - 1) */
};
#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + (pool)->mask) & ~(pool)->mask)
#define JS_ARENA_ALLOCATE(p, pool, nb) \
JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb)
#define JS_ARENA_ALLOCATE_TYPE(p, type, pool) \
JS_ARENA_ALLOCATE_COMMON(p, type *, pool, sizeof(type), 0)
#define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \
JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, _nb > _a->limit)
/*
* NB: In JS_ARENA_ALLOCATE_CAST and JS_ARENA_GROW_CAST, always subtract _nb
* from a->limit rather than adding _nb to _p, to avoid overflow (possible when
* running a 32-bit program on a 64-bit system where the kernel maps the heap
* up against the top of the 32-bit address space, see bug 279273). Note that
* this necessitates a comparison between nb and a->limit that looks like a
* (conceptual) type error but isn't.
*/
#define JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, guard) \
JS_BEGIN_MACRO \
JSArena *_a = (pool)->current; \
size_t _nb = JS_ARENA_ALIGN(pool, nb); \
jsuword _p = _a->avail; \
if ((guard) || _p > _a->limit - _nb) \
_p = (jsuword)JS_ArenaAllocate(pool, _nb); \
else \
_a->avail = _p + _nb; \
p = (type) _p; \
STATIC_ASSUME(!p || ubound((char *)p) >= nb); \
JS_END_MACRO
#define JS_ARENA_GROW(p, pool, size, incr) \
JS_ARENA_GROW_CAST(p, void *, pool, size, incr)
#define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \
JS_BEGIN_MACRO \
JSArena *_a = (pool)->current; \
if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \
/* p was the last thing allocated in the current arena... */ \
size_t _nb = (size) + (incr); \
_nb = JS_ARENA_ALIGN(pool, _nb); \
if (_a->limit >= _nb && (jsuword)(p) <= _a->limit - _nb) { \
/* ... and we have space, so just extend p in-place */ \
_a->avail = (jsuword)(p) + _nb; \
} else if ((jsuword)(p) == _a->base) { \
/* ... p is also the 1st thing in this arena */ \
p = (type) JS_ArenaRealloc(pool, p, size, incr); \
} else { \
/* hard case */ \
p = (type) JS_ArenaGrow(pool, p, size, incr); \
} \
} else { \
/* hard case */ \
p = (type) JS_ArenaGrow(pool, p, size, incr); \
} \
STATIC_ASSUME(!p || ubound((char *)p) >= size + incr); \
JS_END_MACRO
#define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail)
#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q))
/*
* Check if the mark is inside arena's allocated area.
*/
#define JS_IS_IN_ARENA(a, mark) \
(JS_UPTRDIFF(mark, (a)->base) <= JS_UPTRDIFF((a)->avail, (a)->base))
#ifdef DEBUG
#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \
memset((void*)(a)->avail, JS_FREE_PATTERN, \
(a)->limit - (a)->avail))
#define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \
(a)->limit - (jsuword)(a))
#else
#define JS_CLEAR_UNUSED(a) /* nothing */
#define JS_CLEAR_ARENA(a) /* nothing */
#endif
#define JS_ARENA_RELEASE(pool, mark) \
JS_BEGIN_MACRO \
char *_m = (char *)(mark); \
JSArena *_a = (pool)->current; \
if (_a != &(pool)->first && JS_IS_IN_ARENA(_a, _m)) { \
_a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \
JS_ASSERT(_a->avail <= _a->limit); \
JS_CLEAR_UNUSED(_a); \
} else { \
JS_ArenaRelease(pool, _m); \
} \
JS_END_MACRO
#define JS_ARENA_DESTROY(pool, a, pnext) \
JS_BEGIN_MACRO \
JS_COUNT_ARENA(pool,--); \
if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
*(pnext) = (a)->next; \
JS_CLEAR_ARENA(a); \
js::UnwantedForeground::free_(a); \
(a) = NULL; \
JS_END_MACRO
/*
* Initialize an arena pool with a minimum size per arena of |size| bytes.
* |align| must be 1, 2, 4 or 8.
*/
extern JS_PUBLIC_API(void)
JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size,
size_t align);
/*
* Free the arenas in pool. The user may continue to allocate from pool
* after calling this function. There is no need to call JS_InitArenaPool()
* again unless JS_FinishArenaPool(pool) has been called.
*/
extern JS_PUBLIC_API(void)
JS_FreeArenaPool(JSArenaPool *pool);
/*
* Free the arenas in pool and finish using it altogether.
*/
extern JS_PUBLIC_API(void)
JS_FinishArenaPool(JSArenaPool *pool);
/*
* Deprecated do-nothing function.
*/
extern JS_PUBLIC_API(void)
JS_ArenaFinish(void);
/*
* Deprecated do-nothing function.
*/
extern JS_PUBLIC_API(void)
JS_ArenaShutDown(void);
/*
* Friend functions used by the JS_ARENA_*() macros.
*/
extern JS_PUBLIC_API(void *)
JS_ArenaAllocate(JSArenaPool *pool, size_t nb);
extern JS_PUBLIC_API(void *)
JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr);
extern JS_PUBLIC_API(void *)
JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr);
extern JS_PUBLIC_API(void)
JS_ArenaRelease(JSArenaPool *pool, char *mark);
JS_END_EXTERN_C
#ifdef __cplusplus
namespace js {
template <typename T>
inline T *
ArenaArray(JSArenaPool &pool, unsigned count)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, count * sizeof(T));
return (T *) v;
}
template <typename T>
inline T *
ArenaNew(JSArenaPool &pool)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T() : NULL;
}
template <typename T, typename A>
inline T *
ArenaNew(JSArenaPool &pool, const A &a)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T(a) : NULL;
}
template <typename T, typename A, typename B>
inline T *
ArenaNew(JSArenaPool &pool, const A &a, const B &b)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T(a, b) : NULL;
}
template <typename T, typename A, typename B, typename C>
inline T *
ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T(a, b, c) : NULL;
}
template <typename T, typename A, typename B, typename C, typename D>
inline T *
ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c, const D &d)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T(a, b, c, d) : NULL;
}
template <typename T, typename A, typename B, typename C, typename D, typename E>
inline T *
ArenaNew(JSArenaPool &pool, const A &a, const B &b, const C &c, const D &d, const E &e)
{
void *v;
JS_ARENA_ALLOCATE(v, &pool, sizeof(T));
return v ? new (v) T(a, b, c, d, e) : NULL;
}
inline uintN
ArenaAllocatedSize(const JSArenaPool &pool)
{
uintN res = 0;
const JSArena *a = &pool.first;
while (a) {
res += (a->limit - (jsuword)a);
a = a->next;
}
return res;
}
/* Move the contents of oldPool into newPool, and reset oldPool. */
inline void
MoveArenaPool(JSArenaPool *oldPool, JSArenaPool *newPool)
{
*newPool = *oldPool;
JS_InitArenaPool(oldPool, NULL, newPool->arenasize, newPool->mask + 1);
}
} /* namespace js */
#endif /* __cplusplus */
#endif /* jsarena_h___ */

View File

@ -57,7 +57,6 @@
#include "jsstdint.h"
#include "jstypes.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsclist.h"
#include "jsprf.h"
@ -112,6 +111,7 @@ ThreadData::ThreadData()
maxCodeCacheBytes(DEFAULT_JIT_CACHE_SIZE),
#endif
waiveGCQuota(false),
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
dtoaState(NULL),
nativeStackBase(GetNativeStackBase()),
pendingProxyOperation(NULL),
@ -316,9 +316,6 @@ js_PurgeThreads(JSContext *cx)
#endif
}
static const size_t ARENA_HEADER_SIZE_HACK = 40;
static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
JSContext *
js_NewContext(JSRuntime *rt, size_t stackChunkSize)
{
@ -345,9 +342,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
VOUCH_DOES_NOT_REQUIRE_STACK();
JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble));
JS_InitArenaPool(&cx->regExpPool, "regExp", TEMP_POOL_CHUNK_SIZE, sizeof(int));
JS_ASSERT(cx->resolveFlags == 0);
if (!cx->busyArrays.init()) {
@ -1373,9 +1367,6 @@ JSContext::~JSContext()
if (parseMapPool_)
Foreground::delete_<ParseMapPool>(parseMapPool_);
JS_FinishArenaPool(&regExpPool);
JS_FinishArenaPool(&tempPool);
if (lastMessage)
Foreground::free_(lastMessage);
@ -1502,25 +1493,9 @@ JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
return NULL;
}
/*
* Release pool's arenas if the stackPool has existed for longer than the
* limit specified by gcEmptyArenaPoolLifespan.
*/
static void
FreeOldArenas(JSRuntime *rt, JSArenaPool *pool)
{
JSArena *a = pool->current;
if (a == pool->first.next && a->avail == a->base + sizeof(int64)) {
int64 age = JS_Now() - *(int64 *) a->base;
if (age > int64(rt->gcEmptyArenaPoolLifespan) * 1000)
JS_FreeArenaPool(pool);
}
}
void
JSContext::purge()
{
FreeOldArenas(runtime, &regExpPool);
if (!activeCompilations) {
Foreground::delete_<ParseMapPool>(parseMapPool_);
parseMapPool_ = NULL;

View File

@ -46,7 +46,6 @@
#include <string.h>
#include "jsprvtd.h"
#include "jsarena.h"
#include "jsclist.h"
#include "jsatom.h"
#include "jsdhash.h"
@ -64,6 +63,7 @@
#include "jsvector.h"
#include "prmjtime.h"
#include "ds/LifoAlloc.h"
#include "vm/Stack.h"
#include "vm/String.h"
@ -190,6 +190,10 @@ struct ThreadData {
*/
bool waiveGCQuota;
/* Temporary arena pool used while compiling and decompiling. */
static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
LifoAlloc tempLifoAlloc;
/*
* The GSN cache is per thread since even multi-cx-per-thread embeddings
* do not interleave js_GetSrcNote calls.
@ -224,6 +228,7 @@ struct ThreadData {
}
void purge(JSContext *cx) {
tempLifoAlloc.freeUnused();
gsnCache.purge();
/* FIXME: bug 506341. */
@ -994,17 +999,11 @@ struct JSContext
/* Wrap cx->exception for the current compartment. */
void wrapPendingException();
/* Temporary arena pool used while compiling and decompiling. */
JSArenaPool tempPool;
private:
/* Lazily initialized pool of maps used during parse/emit. */
js::ParseMapPool *parseMapPool_;
public:
/* Temporary arena pool used while evaluate regular expressions. */
JSArenaPool regExpPool;
/* Top-level object and pointer to top stack frame's scope chain. */
JSObject *globalObject;
@ -1144,6 +1143,9 @@ struct JSContext
bool hasWErrorOption() const { return hasRunOption(JSOPTION_WERROR); }
bool hasAtLineOption() const { return hasRunOption(JSOPTION_ATLINE); }
js::LifoAlloc &tempLifoAlloc() { return JS_THREAD_DATA(this)->tempLifoAlloc; }
inline js::LifoAlloc &typeLifoAlloc();
#ifdef JS_THREADSAFE
private:
JSThread *thread_;
@ -1877,28 +1879,6 @@ class AutoKeepAtoms {
~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); }
};
class AutoArenaAllocator {
JSArenaPool *pool;
void *mark;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
explicit AutoArenaAllocator(JSArenaPool *pool
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: pool(pool), mark(JS_ARENA_MARK(pool))
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoArenaAllocator() { JS_ARENA_RELEASE(pool, mark); }
template <typename T>
T *alloc(size_t elems) {
void *ptr;
JS_ARENA_ALLOCATE(ptr, pool, elems * sizeof(T));
return static_cast<T *>(ptr);
}
};
class AutoReleasePtr {
JSContext *cx;
void *ptr;

View File

@ -407,6 +407,12 @@ inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
}
#endif
inline js::LifoAlloc &
JSContext::typeLifoAlloc()
{
return compartment->typeLifoAlloc;
}
inline bool
JSContext::ensureGeneratorStackSpace()
{

View File

@ -74,6 +74,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
gcTriggerBytes(0),
gcLastBytes(0),
hold(false),
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
#ifdef JS_TRACER
traceMonitor_(NULL),
#endif
@ -132,11 +133,6 @@ JSCompartment::init(JSContext *cx)
activeAnalysis = activeInference = false;
types.init(cx);
/* Duplicated from jscntxt.cpp. :XXX: bug 675150 fix hack. */
static const size_t ARENA_HEADER_SIZE_HACK = 40;
JS_InitArenaPool(&pool, "analysis", 4096 - ARENA_HEADER_SIZE_HACK, 8);
if (!crossCompartmentWrappers.init())
return false;
@ -622,8 +618,8 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
* Clear the analysis pool, but don't release its data yet. While
* sweeping types any live data will be allocated into the pool.
*/
JSArenaPool oldPool;
MoveArenaPool(&pool, &oldPool);
LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
oldAlloc.steal(&typeLifoAlloc);
/*
* Sweep analysis information and everything depending on it from the
@ -656,9 +652,6 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
JSScript *script = i.get<JSScript>();
script->clearAnalysis();
}
/* Reset the analysis pool, releasing all analysis and intermediate type data. */
JS_FinishArenaPool(&oldPool);
}
active = false;

View File

@ -408,7 +408,8 @@ struct JS_FRIEND_API(JSCompartment) {
* Cleared on every GC, unless the GC happens during analysis (indicated
* by activeAnalysis, which is implied by activeInference).
*/
JSArenaPool pool;
static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
js::LifoAlloc typeLifoAlloc;
bool activeAnalysis;
bool activeInference;

View File

@ -485,10 +485,9 @@ JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
return NULL;
/* Munge data into the API this method implements. Avert your eyes! */
*markp = JS_ARENA_MARK(&cx->tempPool);
*markp = cx->tempLifoAlloc().mark();
jsuword *names;
JS_ARENA_ALLOCATE_CAST(names, jsuword *, &cx->tempPool, localNames.length() * sizeof *names);
jsuword *names = cx->tempLifoAlloc().newArray<jsuword>(localNames.length());
if (!names) {
js_ReportOutOfMemory(cx);
return NULL;
@ -513,7 +512,7 @@ JS_AtomKey(JSAtom *atom)
extern JS_PUBLIC_API(void)
JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark)
{
JS_ARENA_RELEASE(&cx->tempPool, mark);
cx->tempLifoAlloc().release(mark);
}
JS_PUBLIC_API(JSScript *)
@ -2167,9 +2166,9 @@ JS_PUBLIC_API(void)
JS_DumpBytecode(JSContext *cx, JSScript *script)
{
#if defined(DEBUG)
AutoArenaAllocator mark(&cx->tempPool);
LifoAlloc lifoAlloc(1024);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
js_Disassemble(cx, script, true, &sprinter);

View File

@ -48,7 +48,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsbit.h"
#include "jsprf.h"
@ -75,6 +74,7 @@
#include "jsscriptinlines.h"
#include "frontend/ParseMaps-inl.h"
#include "ds/LifoAlloc.h"
/* Allocation chunk counts, must be powers of two in general. */
#define BYTECODE_CHUNK_LENGTH 1024 /* initial bytecode chunk length */
@ -515,8 +515,7 @@ AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp)
if (jt) {
cg->jtFreeList = jt->kids[JT_LEFT];
} else {
JS_ARENA_ALLOCATE_CAST(jt, JSJumpTarget *, &args->cx->tempPool,
sizeof *jt);
jt = args->cx->tempLifoAlloc().new_<JSJumpTarget>();
if (!jt) {
js_ReportOutOfMemory(args->cx);
return 0;
@ -3312,9 +3311,7 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
static Value *
AllocateSwitchConstant(JSContext *cx)
{
Value *pv;
JS_ARENA_ALLOCATE_TYPE(pv, Value, &cx->tempPool);
return pv;
return cx->tempLifoAlloc().new_<Value>();
}
/*
@ -7752,14 +7749,12 @@ static JSBool
NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
uintN stackDepth, size_t start, size_t end)
{
JSTryNode *tryNode;
JS_ASSERT((uintN)(uint16)stackDepth == stackDepth);
JS_ASSERT(start <= end);
JS_ASSERT((size_t)(uint32)start == start);
JS_ASSERT((size_t)(uint32)end == end);
JS_ARENA_ALLOCATE_TYPE(tryNode, JSTryNode, &cx->tempPool);
JSTryNode *tryNode = cx->tempLifoAlloc().new_<JSTryNode>();
if (!tryNode) {
js_ReportOutOfMemory(cx);
return JS_FALSE;

View File

@ -668,11 +668,9 @@ struct JSCodeGenerator : public JSTreeContext
}
/*
* Release cg->codePool, cg->notePool, and parser->context->tempPool to
* marks set by JSCodeGenerator's ctor. Note that cgs are magic: they own
* the arena pool "tops-of-stack" space above their codeMark, noteMark, and
* tempMark points. This means you cannot alloc from tempPool and save the
* pointer beyond the next JSCodeGenerator destructor call.
* Note that cgs are magic: they own the arena "top-of-stack" space above
* their tempMark points. This means that you cannot alloc from tempPool
* and save the pointer beyond the next JSCodeGenerator destructor call.
*/
~JSCodeGenerator();

View File

@ -2181,8 +2181,8 @@ Function(JSContext *cx, uintN argc, Value *vp)
* for a terminating 0. Mark cx->tempPool for later release, to free
* collected_args and its tokenstream in one swoop.
*/
AutoArenaAllocator aaa(&cx->tempPool);
jschar *cp = aaa.alloc<jschar>(args_length + 1);
LifoAllocScope las(&cx->tempLifoAlloc());
jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);
if (!cp) {
js_ReportOutOfMemory(cx);
return false;

View File

@ -352,7 +352,7 @@ TypeSet::make(JSContext *cx, const char *name)
{
JS_ASSERT(cx->compartment->activeInference);
TypeSet *res = ArenaNew<TypeSet>(cx->compartment->pool);
TypeSet *res = cx->typeLifoAlloc().new_<TypeSet>();
if (!res) {
cx->compartment->types.setPendingNukeTypes(cx);
return NULL;
@ -492,7 +492,7 @@ public:
void
TypeSet::addSubset(JSContext *cx, TypeSet *target)
{
add(cx, ArenaNew<TypeConstraintSubset>(cx->compartment->pool, target));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
}
/* Constraints for reads/writes on object properties. */
@ -527,14 +527,14 @@ void
TypeSet::addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
TypeSet *target, jsid id)
{
add(cx, ArenaNew<TypeConstraintProp>(cx->compartment->pool, script, pc, target, id, false));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintProp>(script, pc, target, id, false));
}
void
TypeSet::addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
TypeSet *target, jsid id)
{
add(cx, ArenaNew<TypeConstraintProp>(cx->compartment->pool, script, pc, target, id, true));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintProp>(script, pc, target, id, true));
}
/*
@ -575,7 +575,7 @@ TypeSet::addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid i
if (JSOp(*callpc) == JSOP_NEW)
return;
add(cx, ArenaNew<TypeConstraintCallProp>(cx->compartment->pool, script, callpc, id));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintCallProp>(script, callpc, id));
}
/*
@ -608,8 +608,8 @@ void
TypeSet::addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
TypeSet *objectTypes, TypeSet *valueTypes)
{
add(cx, ArenaNew<TypeConstraintSetElement>(cx->compartment->pool, script, pc,
objectTypes, valueTypes));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintSetElement>(script, pc, objectTypes,
valueTypes));
}
/*
@ -633,7 +633,7 @@ public:
void
TypeSet::addCall(JSContext *cx, TypeCallsite *site)
{
add(cx, ArenaNew<TypeConstraintCall>(cx->compartment->pool, site));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintCall>(site));
}
/* Constraints for arithmetic operations. */
@ -658,7 +658,7 @@ public:
void
TypeSet::addArith(JSContext *cx, TypeSet *target, TypeSet *other)
{
add(cx, ArenaNew<TypeConstraintArith>(cx->compartment->pool, target, other));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(target, other));
}
/* Subset constraint which transforms primitive values into appropriate objects. */
@ -678,7 +678,7 @@ public:
void
TypeSet::addTransformThis(JSContext *cx, JSScript *script, TypeSet *target)
{
add(cx, ArenaNew<TypeConstraintTransformThis>(cx->compartment->pool, script, target));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintTransformThis>(script, target));
}
/*
@ -709,7 +709,7 @@ TypeSet::addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type
if (JSOp(*callpc) == JSOP_NEW)
return;
add(cx, ArenaNew<TypeConstraintPropagateThis>(cx->compartment->pool, script, callpc, type, types));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
}
/* Subset constraint which filters out primitive types. */
@ -752,7 +752,7 @@ public:
void
TypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter)
{
add(cx, ArenaNew<TypeConstraintFilterPrimitive>(cx->compartment->pool, target, filter));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFilterPrimitive>(target, filter));
}
/* If id is a normal slotful 'own' property of an object, get its shape. */
@ -876,7 +876,7 @@ public:
void
TypeSet::addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
{
add(cx, ArenaNew<TypeConstraintSubsetBarrier>(cx->compartment->pool, script, pc, target));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubsetBarrier>(script, pc, target));
}
/*
@ -904,7 +904,7 @@ public:
void
TypeSet::addLazyArguments(JSContext *cx, TypeSet *target)
{
add(cx, ArenaNew<TypeConstraintLazyArguments>(cx->compartment->pool, target));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintLazyArguments>(target));
}
/////////////////////////////////////////////////////////////////////
@ -1086,9 +1086,8 @@ TypeConstraintCallProp::newType(JSContext *cx, TypeSet *source, Type type)
if (!types->hasPropagatedProperty())
object->getFromPrototypes(cx, id, types);
/* Bypass addPropagateThis, we already have the callpc. */
types->add(cx, ArenaNew<TypeConstraintPropagateThis>(cx->compartment->pool,
script, callpc, type,
(TypeSet *) NULL));
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
script, callpc, type, (TypeSet *) NULL));
}
}
}
@ -1389,8 +1388,8 @@ public:
void
TypeSet::addFreeze(JSContext *cx)
{
add(cx, ArenaNew<TypeConstraintFreeze>(cx->compartment->pool,
cx->compartment->types.compiledScript), false);
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreeze>(
cx->compartment->types.compiledScript), false);
}
/*
@ -1473,8 +1472,8 @@ TypeSet::getKnownTypeTag(JSContext *cx)
JS_ASSERT_IF(empty, type == JSVAL_TYPE_UNKNOWN);
if (cx->compartment->types.compiledScript && (empty || type != JSVAL_TYPE_UNKNOWN)) {
add(cx, ArenaNew<TypeConstraintFreezeTypeTag>(cx->compartment->pool,
cx->compartment->types.compiledScript), false);
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeTypeTag>(
cx->compartment->types.compiledScript), false);
}
return type;
@ -1553,9 +1552,8 @@ public:
TypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
if (!types)
return;
types->add(cx,
ArenaNew<TypeConstraintFreezeObjectFlags>(cx->compartment->pool,
script, flags, &marked), false);
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
script, flags, &marked), false);
return;
}
} else {
@ -1596,8 +1594,8 @@ TypeSet::hasObjectFlags(JSContext *cx, TypeObjectFlags flags)
* Watch for new objects of different kind, and re-traverse existing types
* in this set to add any needed FreezeArray constraints.
*/
add(cx, ArenaNew<TypeConstraintFreezeObjectFlagsSet>(cx->compartment->pool,
cx->compartment->types.compiledScript, flags));
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlagsSet>(
cx->compartment->types.compiledScript, flags));
return false;
}
@ -1611,9 +1609,8 @@ TypeSet::HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags
TypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
if (!types)
return true;
types->add(cx,
ArenaNew<TypeConstraintFreezeObjectFlags>(cx->compartment->pool,
cx->compartment->types.compiledScript, flags), false);
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
cx->compartment->types.compiledScript, flags), false);
return false;
}
@ -1694,9 +1691,9 @@ TypeSet::WatchObjectStateChange(JSContext *cx, TypeObject *obj)
* Use a constraint which triggers recompilation when markStateChange is
* called, which will set 'force' to true.
*/
types->add(cx, ArenaNew<TypeConstraintFreezeObjectFlags>(cx->compartment->pool,
cx->compartment->types.compiledScript,
0));
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
cx->compartment->types.compiledScript,
0));
}
class TypeConstraintFreezeOwnProperty : public TypeConstraint
@ -1749,7 +1746,7 @@ TypeSet::isOwnProperty(JSContext *cx, TypeObject *object, bool configurable)
if (isOwnProperty(configurable))
return true;
add(cx, ArenaNew<TypeConstraintFreezeOwnProperty>(cx->compartment->pool,
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeOwnProperty>(
cx->compartment->types.compiledScript,
configurable), false);
return false;
@ -1761,8 +1758,8 @@ TypeSet::knownNonEmpty(JSContext *cx)
if (baseFlags() != 0 || baseObjectCount() != 0)
return true;
add(cx, ArenaNew<TypeConstraintFreeze>(cx->compartment->pool,
cx->compartment->types.compiledScript), false);
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreeze>(
cx->compartment->types.compiledScript), false);
return false;
}
@ -1821,7 +1818,7 @@ TypeSet::getSingleton(JSContext *cx, bool freeze)
return NULL;
if (freeze) {
add(cx, ArenaNew<TypeConstraintFreeze>(cx->compartment->pool,
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreeze>(
cx->compartment->types.compiledScript), false);
}
@ -1879,9 +1876,8 @@ TypeSet::hasGlobalObject(JSContext *cx, JSObject *global)
return false;
}
add(cx, ArenaNew<TypeConstraintFreezeGlobal>(cx->compartment->pool,
cx->compartment->types.compiledScript,
global), false);
add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeGlobal>(
cx->compartment->types.compiledScript, global), false);
return true;
}
@ -2309,8 +2305,7 @@ ScriptAnalysis::addTypeBarrier(JSContext *cx, const jsbytecode *pc, TypeSet *tar
InferSpewColor(target), target, InferSpewColorReset(),
TypeString(type));
barrier = ArenaNew<TypeBarrier>(cx->compartment->pool, target, type,
(JSObject *) NULL, JSID_VOID);
barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, type, (JSObject *) NULL, JSID_VOID);
barrier->next = code.typeBarriers;
code.typeBarriers = barrier;
@ -2335,8 +2330,7 @@ ScriptAnalysis::addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc, Typ
InferSpewColor(target), target, InferSpewColorReset(),
(void *) singleton, TypeIdString(singletonId));
TypeBarrier *barrier =
ArenaNew<TypeBarrier>(cx->compartment->pool, target, Type::UndefinedType(),
TypeBarrier *barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(),
singleton, singletonId);
barrier->next = code.typeBarriers;
@ -2701,7 +2695,7 @@ bool
TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
{
JS_ASSERT(!*pprop);
Property *base = ArenaNew<Property>(cx->compartment->pool, id);
Property *base = cx->typeLifoAlloc().new_<Property>(id);
if (!base) {
cx->compartment->types.setPendingNukeTypes(cx);
return false;
@ -3251,7 +3245,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
if (ExtendedDef(pc))
defCount++;
TypeSet *pushed = ArenaArray<TypeSet>(cx->compartment->pool, defCount);
TypeSet *pushed = cx->typeLifoAlloc().newArrayUninitialized<TypeSet>(defCount);
if (!pushed)
return false;
PodZero(pushed, defCount);
@ -3774,7 +3768,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
/* Construct the base call information about this site. */
unsigned argCount = GetUseCount(script, offset) - 2;
TypeCallsite *callsite = ArenaNew<TypeCallsite>(cx->compartment->pool,
TypeCallsite *callsite = cx->typeLifoAlloc().new_<TypeCallsite>(
cx, script, pc, op == JSOP_NEW, argCount);
if (!callsite || (argCount && !callsite->argumentTypes)) {
cx->compartment->types.setPendingNukeTypes(cx);
@ -4496,8 +4490,7 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
if (!parentTypes || parentTypes->unknown())
return false;
parentObject->getFromPrototypes(cx, id, parentTypes);
parentTypes->add(cx,
ArenaNew<TypeConstraintClearDefiniteSetter>(cx->compartment->pool, type));
parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSetter>(type));
} else if (op == JSOP_FUNCALL && uses->u.which == GET_ARGC(pc) - 1) {
/*
* Passed as the first parameter to Function.call. Follow control
@ -4546,9 +4539,9 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
* should the Function.call or callee itself change in the future.
*/
analysis->pushedTypes(calleev.pushedOffset(), 0)->add(cx,
ArenaNew<TypeConstraintClearDefiniteSingle>(cx->compartment->pool, type));
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
analysis->pushedTypes(calleev.pushedOffset(), 1)->add(cx,
ArenaNew<TypeConstraintClearDefiniteSingle>(cx->compartment->pool, type));
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
TypeNewScript::Initializer pushframe(TypeNewScript::Initializer::FRAME_PUSH, uses->offset);
if (!initializerList->append(pushframe)) {
@ -5424,7 +5417,7 @@ JSScript::makeAnalysis(JSContext *cx)
AutoEnterAnalysis enter(cx);
types->analysis = ArenaNew<ScriptAnalysis>(cx->compartment->pool, this);
types->analysis = cx->typeLifoAlloc().new_<ScriptAnalysis>(this);
if (!types->analysis)
return false;
@ -5815,7 +5808,7 @@ TypeObject::sweep(JSContext *cx)
for (unsigned i = 0; i < oldCapacity; i++) {
Property *prop = oldArray[i];
if (prop && prop->types.isOwnProperty(false)) {
Property *newProp = ArenaNew<Property>(compartment->pool, *prop);
Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
Property **pentry =
HashSetInsert<jsid,Property,Property>
@ -5835,7 +5828,7 @@ TypeObject::sweep(JSContext *cx)
} else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
if (prop->types.isOwnProperty(false)) {
Property *newProp = ArenaNew<Property>(compartment->pool, *prop);
Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(cx, compartment);
@ -6109,7 +6102,7 @@ JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
* by being copied to the replacement pool. This memory will be counted too
* and deducted from the amount of temporary data.
*/
stats->temporary += ArenaAllocatedSize(compartment->pool);
stats->temporary += compartment->typeLifoAlloc.used();
/* Pending arrays are cleared on GC along with the analysis pool. */
stats->temporary += sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;

View File

@ -43,29 +43,16 @@
#define jsinfer_h___
#include "jsalloc.h"
#include "jsarena.h"
#include "jscell.h"
#include "jstl.h"
#include "jsprvtd.h"
#include "jshashtable.h"
namespace js {
class CallArgs;
namespace analyze {
class ScriptAnalysis;
}
class GlobalObject;
}
#include "ds/LifoAlloc.h"
namespace js {
namespace types {
/* Forward declarations. */
class TypeSet;
struct TypeCallsite;
struct TypeObject;
struct TypeCompartment;
/* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
struct TypeObjectKey {
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }

View File

@ -820,7 +820,7 @@ HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key
return &values[insertpos];
}
U **newValues = ArenaArray<U*>(compartment->pool, newCapacity);
U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
if (!newValues)
return NULL;
PodZero(newValues, newCapacity);
@ -861,7 +861,7 @@ HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
if (KEY::getKey(oldData) == key)
return (U **) &values;
values = ArenaArray<U*>(compartment->pool, SET_ARRAY_SIZE);
values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
if (!values) {
values = (U **) oldData;
return NULL;
@ -1097,7 +1097,7 @@ TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
thisTypes(NULL), returnTypes(NULL)
{
/* Caller must check for failure. */
argumentTypes = ArenaArray<TypeSet*>(cx->compartment->pool, argumentCount);
argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
}
/////////////////////////////////////////////////////////////////////

View File

@ -46,7 +46,6 @@
#include <math.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsprf.h"
#include "jsapi.h"

View File

@ -45,7 +45,6 @@
#include "jstypes.h"
#include "jsstdint.h"
#include "jsutil.h"
#include "jsarena.h"
#include "jsapi.h"
#include "jsarray.h"
#include "jsatom.h"

View File

@ -45,7 +45,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsbit.h"
#include "jsutil.h"
#include "jshash.h"

View File

@ -41,7 +41,6 @@
#include <string.h>
#include "jsapi.h"
#include "jsarena.h"
#include "jsarray.h"
#include "jsatom.h"
#include "jsbool.h"

View File

@ -50,7 +50,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsprf.h"
#include "jsapi.h"
@ -319,9 +318,7 @@ js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, jsbytecode *pc
else
SprintCString(sp, " ");
}
len = js_Disassemble1(cx, script, next,
next - script->code,
lines, sp);
len = js_Disassemble1(cx, script, next, next - script->code, lines, sp);
if (!len)
return JS_FALSE;
next += len;
@ -338,24 +335,22 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, Sprinter *sp)
JS_FRIEND_API(JSBool)
js_DumpPC(JSContext *cx)
{
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
JSBool ok = js_DisassembleAtPC(cx, cx->fp()->script(), true, cx->regs().pc, &sprinter);
fprintf(stdout, "%s", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return ok;
}
JSBool
js_DumpScript(JSContext *cx, JSScript *script)
{
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
JSBool ok = js_Disassemble(cx, script, true, &sprinter);
fprintf(stdout, "%s", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
return ok;
}
@ -367,13 +362,13 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
{
if (JSVAL_IS_STRING(v)) {
Sprinter sprinter;
void *mark = JS_ARENA_MARK(&cx->tempPool);
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
LifoAlloc &tla = cx->tempLifoAlloc();
LifoAllocScope las(&tla);
INIT_SPRINTER(cx, &sprinter, &tla, 0);
char *nbytes = QuoteString(&sprinter, JSVAL_TO_STRING(v), '"');
if (!nbytes)
return false;
nbytes = JS_sprintf_append(NULL, "%s", nbytes);
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!nbytes)
return false;
bytes->initBytes(nbytes);
@ -687,11 +682,10 @@ SprintEnsureBuffer(Sprinter *sp, size_t len)
if (nb < 0)
return JS_TRUE;
base = sp->base;
if (!base) {
JS_ARENA_ALLOCATE_CAST(base, char *, sp->pool, nb);
} else {
JS_ARENA_GROW_CAST(base, char *, sp->pool, sp->size, nb);
}
if (!base)
base = static_cast<char *>(sp->pool->allocUnaligned(nb));
else
base = static_cast<char *>(sp->pool->reallocUnaligned(base, sp->size, nb));
if (!base) {
js_ReportOutOfMemory(sp->context);
return JS_FALSE;
@ -876,16 +870,11 @@ QuoteString(Sprinter *sp, JSString *str, uint32 quote)
JSString *
js_QuoteString(JSContext *cx, JSString *str, jschar quote)
{
void *mark;
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
char *bytes;
JSString *escstr;
mark = JS_ARENA_MARK(&cx->tempPool);
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
bytes = QuoteString(&sprinter, str, quote);
escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
JS_ARENA_RELEASE(&cx->tempPool, mark);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
char *bytes = QuoteString(&sprinter, str, quote);
JSString *escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
return escstr;
}
@ -893,7 +882,7 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote)
struct JSPrinter {
Sprinter sprinter; /* base class state */
JSArenaPool pool; /* string allocation pool */
LifoAlloc pool; /* string allocation pool */
uintN indent; /* indentation in spaces */
bool pretty; /* pretty-print: indent, use newlines */
bool grouped; /* in parenthesized expression context */
@ -909,13 +898,11 @@ JSPrinter *
js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
uintN indent, JSBool pretty, JSBool grouped, JSBool strict)
{
JSPrinter *jp;
jp = (JSPrinter *) cx->malloc_(sizeof(JSPrinter));
JSPrinter *jp = (JSPrinter *) cx->malloc_(sizeof(JSPrinter));
if (!jp)
return NULL;
INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
JS_InitArenaPool(&jp->pool, name, 256, 1);
new (&jp->pool) LifoAlloc(1024);
jp->indent = indent;
jp->pretty = !!pretty;
jp->grouped = !!grouped;
@ -938,7 +925,7 @@ js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun,
void
js_DestroyPrinter(JSPrinter *jp)
{
JS_FinishArenaPool(&jp->pool);
jp->pool.freeAll();
Foreground::delete_(jp->localNames);
jp->sprinter.context->free_(jp);
}
@ -955,7 +942,7 @@ js_GetPrinterOutput(JSPrinter *jp)
str = JS_NewStringCopyZ(cx, jp->sprinter.base);
if (!str)
return NULL;
JS_FreeArenaPool(&jp->pool);
jp->pool.freeAll();
INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
return str;
}
@ -1906,15 +1893,12 @@ DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
static JSBool
InitSprintStack(JSContext *cx, SprintStack *ss, JSPrinter *jp, uintN depth)
{
size_t offsetsz, opcodesz;
void *space;
INIT_SPRINTER(cx, &ss->sprinter, &cx->tempPool, PAREN_SLOP);
INIT_SPRINTER(cx, &ss->sprinter, &cx->tempLifoAlloc(), PAREN_SLOP);
/* Allocate the parallel (to avoid padding) offset and opcode stacks. */
offsetsz = depth * sizeof(ptrdiff_t);
opcodesz = depth * sizeof(jsbytecode);
JS_ARENA_ALLOCATE(space, &cx->tempPool, offsetsz + opcodesz);
size_t offsetsz = depth * sizeof(ptrdiff_t);
size_t opcodesz = depth * sizeof(jsbytecode);
void *space = cx->tempLifoAlloc().alloc(offsetsz + opcodesz);
if (!space) {
js_ReportOutOfMemory(cx);
return JS_FALSE;
@ -4064,7 +4048,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#if JS_HAS_GENERATOR_EXPRS
sn = js_GetSrcNote(jp->script, pc);
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
void *mark;
Vector<JSAtom *> *innerLocalNames;
Vector<JSAtom *> *outerLocalNames;
JSScript *inner, *outer;
@ -4079,7 +4062,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* Therefore after InitSprintStack succeeds, we must
* release to mark before returning.
*/
mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
if (fun->script()->bindings.hasLocalNames()) {
innerLocalNames = cx->new_<Vector<JSAtom *> >(cx);
if (!innerLocalNames ||
@ -4091,10 +4074,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
innerLocalNames = NULL;
}
inner = fun->script();
if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner)))
return NULL;
}
ss2.inGenExp = JS_TRUE;
/*
@ -4122,10 +4103,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
jp->script = outer;
jp->fun = outerfun;
jp->localNames = outerLocalNames;
if (!ok) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!ok)
return NULL;
}
/*
* Advance over this op and its global |this| push, and
@ -4195,7 +4174,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* from cx's tempPool.
*/
rval = JS_strdup(cx, PopStr(&ss2, op));
JS_ARENA_RELEASE(&cx->tempPool, mark);
las.releaseEarly();
if (!rval)
return NULL;
todo = SprintCString(&ss->sprinter, rval);
@ -4833,8 +4812,6 @@ DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
uintN depth, i;
SprintStack ss;
JSContext *cx;
void *mark;
JSBool ok;
JSScript *oldscript;
char *last;
@ -4845,10 +4822,9 @@ DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
AutoScriptUntrapper untrapper(cx, script, &pc);
/* Initialize a sprinter for use with the offset stack. */
mark = JS_ARENA_MARK(&cx->tempPool);
ok = InitSprintStack(cx, &ss, jp, depth);
if (!ok)
goto out;
LifoAllocScope las(&cx->tempLifoAlloc());
if (!InitSprintStack(cx, &ss, jp, depth))
return false;
/*
* If we are called from js_DecompileValueGenerator with a portion of
@ -4872,7 +4848,7 @@ DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
/* Call recursive subroutine to do the hard work. */
oldscript = jp->script;
jp->script = script;
ok = Decompile(&ss, pc, len, JSOP_NOP) != NULL;
bool ok = Decompile(&ss, pc, len, JSOP_NOP) != NULL;
jp->script = oldscript;
/* If the given code didn't empty the stack, do it now. */
@ -4883,9 +4859,6 @@ DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
js_printf(jp, "%s", last);
}
out:
/* Free all temporary stuff allocated under this call. */
JS_ARENA_RELEASE(&cx->tempPool, mark);
return ok;
}
@ -4998,7 +4971,6 @@ js_DecompileFunction(JSPrinter *jp)
JSScript *script = fun->script();
#if JS_HAS_DESTRUCTURING
SprintStack ss;
void *mark;
#endif
/* Print the parameters. */
@ -5010,7 +4982,7 @@ js_DecompileFunction(JSPrinter *jp)
#if JS_HAS_DESTRUCTURING
ss.printer = NULL;
jp->script = script;
mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool);
LifoAllocScope las(&jp->sprinter.context->tempLifoAlloc());
#endif
for (i = 0; i < fun->nargs; i++) {
@ -5061,7 +5033,7 @@ js_DecompileFunction(JSPrinter *jp)
#if JS_HAS_DESTRUCTURING
jp->script = NULL;
JS_ARENA_RELEASE(&jp->sprinter.context->tempPool, mark);
las.releaseEarly();
#endif
if (!ok)
return JS_FALSE;

View File

@ -46,7 +46,6 @@
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsutil.h"
#include "jsarena.h"
JS_BEGIN_EXTERN_C
@ -505,7 +504,7 @@ DecompileValueGenerator(JSContext *cx, intN spindex, const Value &v,
*/
struct Sprinter {
JSContext *context; /* context executing the decompiler */
JSArenaPool *pool; /* string allocation pool */
LifoAlloc *pool; /* string allocation pool */
char *base; /* base address of buffer in pool */
size_t size; /* size of buffer allocated at base */
ptrdiff_t offset; /* offset of next free char in buffer */

View File

@ -56,7 +56,6 @@
#include <math.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsapi.h"
#include "jsarray.h"
@ -209,9 +208,9 @@ Parser::init(const jschar *base, size_t length, const char *filename, uintN line
JSContext *cx = context;
if (!cx->ensureParseMapPool())
return false;
tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
tempPoolMark = cx->tempLifoAlloc().mark();
if (!tokenStream.init(base, length, filename, lineno, version)) {
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
cx->tempLifoAlloc().release(tempPoolMark);
return false;
}
return true;
@ -223,7 +222,7 @@ Parser::~Parser()
if (principals)
JSPRINCIPALS_DROP(cx, principals);
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
cx->tempLifoAlloc().release(tempPoolMark);
cx->activeCompilations--;
}
@ -247,8 +246,7 @@ Parser::newObjectBox(JSObject *obj)
* containing the entries must be alive until we are done with scanning,
* parsing and code generation for the whole script or top-level function.
*/
JSObjectBox *objbox;
JS_ARENA_ALLOCATE_TYPE(objbox, JSObjectBox, &context->tempPool);
JSObjectBox *objbox = context->tempLifoAlloc().new_<JSObjectBox>();
if (!objbox) {
js_ReportOutOfMemory(context);
return NULL;
@ -273,8 +271,7 @@ Parser::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc)
* containing the entries must be alive until we are done with scanning,
* parsing and code generation for the whole script or top-level function.
*/
JSFunctionBox *funbox;
JS_ARENA_ALLOCATE_TYPE(funbox, JSFunctionBox, &context->tempPool);
JSFunctionBox *funbox = context->tempLifoAlloc().newPod<JSFunctionBox>();
if (!funbox) {
js_ReportOutOfMemory(context);
return NULL;
@ -677,8 +674,7 @@ NewOrRecycledNode(JSTreeContext *tc)
pn = tc->parser->nodeList;
if (!pn) {
JSContext *cx = tc->parser->context;
JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
pn = cx->tempLifoAlloc().new_<JSParseNode>();
if (!pn)
js_ReportOutOfMemory(cx);
} else {

View File

@ -159,6 +159,8 @@ class UpvarCookie;
class TempAllocPolicy;
class RuntimeAllocPolicy;
class GlobalObject;
template <class T,
size_t MinInlineCapacity = 0,
class AllocPolicy = TempAllocPolicy>
@ -183,6 +185,8 @@ template <typename K,
size_t InlineElems>
class InlineMap;
class LifoAlloc;
class PropertyCache;
struct PropertyCacheEntry;
@ -210,6 +214,26 @@ typedef JSPropertyOp PropertyOp;
typedef JSStrictPropertyOp StrictPropertyOp;
typedef JSPropertyDescriptor PropertyDescriptor;
namespace analyze {
struct LifetimeVariable;
class LoopAnalysis;
class ScriptAnalysis;
class SlotValue;
class SSAValue;
class SSAUseChain;
} /* namespace analyze */
namespace types {
class TypeSet;
struct TypeCallsite;
struct TypeObject;
struct TypeCompartment;
} /* namespace types */
} /* namespace js */
} /* export "C++" */

View File

@ -149,7 +149,6 @@ class RegExp
void reportPCREError(JSContext *cx, int error);
#endif
void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
static inline bool initArena(JSContext *cx);
static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
inline bool executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
@ -255,27 +254,6 @@ class RegExpMatchBuilder
/* RegExp inlines. */
inline bool
RegExp::initArena(JSContext *cx)
{
if (cx->regExpPool.first.next)
return true;
/*
* The regular expression arena pool is special... we want to hang on to it
* until a GC is performed so rapid subsequent regexp executions don't
* thrash malloc/freeing arena chunks.
*
* Stick a timestamp at the base of that pool.
*/
int64 *timestamp;
JS_ARENA_ALLOCATE_CAST(timestamp, int64 *, &cx->regExpPool, sizeof *timestamp);
if (!timestamp)
return false;
*timestamp = JS_Now();
return true;
}
inline void
RegExp::checkMatchPairs(JSString *input, int *buf, size_t matchItemCount)
{
@ -339,11 +317,8 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
const size_t matchItemCount = pairCount * 2;
if (!initArena(cx))
return false;
AutoArenaAllocator aaa(&cx->regExpPool);
int *buf = aaa.alloc<int>(bufCount);
LifoAllocScope las(&cx->tempLifoAlloc());
int *buf = cx->tempLifoAlloc().newArray<int>(bufCount);
if (!buf)
return false;

View File

@ -54,7 +54,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsbit.h"
#include "jsutil.h"
#include "jsprf.h"

View File

@ -46,7 +46,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsbit.h"
#include "jsclist.h"
#include "jsdhash.h"

View File

@ -384,14 +384,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
Bindings bindings(cx);
uint32 nameCount = nargs + nvars + nupvars;
if (nameCount > 0) {
struct AutoMark {
JSArenaPool * const pool;
void * const mark;
AutoMark(JSArenaPool *pool) : pool(pool), mark(JS_ARENA_MARK(pool)) { }
~AutoMark() {
JS_ARENA_RELEASE(pool, mark);
}
} automark(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
/*
* To xdr the names we prefix the names with a bitmap descriptor and
@ -402,9 +395,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
* name is declared as const, not as ordinary var.
* */
uintN bitmapLength = JS_HOWMANY(nameCount, JS_BITS_PER_UINT32);
uint32 *bitmap;
JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &cx->tempPool,
bitmapLength * sizeof *bitmap);
uint32 *bitmap = cx->tempLifoAlloc().newArray<uint32>(bitmapLength);
if (!bitmap) {
js_ReportOutOfMemory(cx);
return false;

View File

@ -146,8 +146,6 @@ typedef struct JSConstArray {
uint32 length;
} JSConstArray;
struct JSArenaPool;
namespace js {
struct GlobalSlotArray {

View File

@ -40,7 +40,7 @@
#ifndef jstl_h_
#define jstl_h_
#include "jspubtd.h"
#include "jsprvtd.h"
#include "jsbit.h"
#include "jsstaticcheck.h"
#include "jsstdint.h"
@ -167,6 +167,7 @@ template <> struct IsPodType<long long> { static const bool result =
template <> struct IsPodType<unsigned long long> { static const bool result = true; };
template <> struct IsPodType<float> { static const bool result = true; };
template <> struct IsPodType<double> { static const bool result = true; };
template <> struct IsPodType<wchar_t> { static const bool result = true; };
template <typename T> struct IsPodType<T *> { static const bool result = true; };
/* Return the size/end of an array without using macros. */

View File

@ -7390,9 +7390,9 @@ TraceRecorder::monitorRecording(JSOp op)
debug_only_stmt(
if (LogController.lcbits & LC_TMRecorder) {
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
debug_only_print0(LC_TMRecorder, "\n");
js_Disassemble1(cx, cx->fp()->script(), cx->regs().pc,
@ -7401,7 +7401,6 @@ TraceRecorder::monitorRecording(JSOp op)
!cx->fp()->hasImacropc(), &sprinter);
fprintf(stdout, "%s", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
}
)
@ -10415,14 +10414,13 @@ TraceRecorder::record_EnterFrame()
callDepth);
debug_only_stmt(
if (LogController.lcbits & LC_TMRecorder) {
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
js_Disassemble(cx, cx->fp()->script(), JS_TRUE, &sprinter);
debug_only_printf(LC_TMTracer, "%s", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
debug_only_print0(LC_TMTracer, "----\n");
}
)

View File

@ -70,6 +70,8 @@ using namespace mozilla;
JS_BEGIN_EXTERN_C
#define JS_UPTRDIFF(a_, b_) (uintptr_t(a_) - uintptr_t(b_))
#define JS_CRASH_UNLESS(__cond) \
JS_BEGIN_MACRO \
if (!(__cond)) { \

View File

@ -1462,13 +1462,12 @@ public:
JS_BEGIN_MACRO \
if (IsJaegerSpewChannelActive(JSpew_JSOps)) { \
JaegerSpew(JSpew_JSOps, " %2d ", frame.stackDepth()); \
void *mark = JS_ARENA_MARK(&cx->tempPool); \
LifoAllocScope las(&cx->tempLifoAlloc()); \
Sprinter sprinter; \
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0); \
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0); \
js_Disassemble1(cx, script, PC, PC - script->code, \
JS_TRUE, &sprinter); \
fprintf(stdout, "%s", sprinter.base); \
JS_ARENA_RELEASE(&cx->tempPool, mark); \
} \
JS_END_MACRO;
#else
@ -6683,7 +6682,7 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow, bool *tramp
if (cx->typeInferenceEnabled()) {
RegisterAllocation *&alloc = analysis->getAllocation(target);
if (!alloc) {
alloc = ArenaNew<RegisterAllocation>(cx->compartment->pool, false);
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
if (!alloc)
return false;
}

View File

@ -575,7 +575,7 @@ RegisterAllocation *
FrameState::computeAllocation(jsbytecode *target)
{
JS_ASSERT(cx->typeInferenceEnabled());
RegisterAllocation *alloc = ArenaNew<RegisterAllocation>(cx->compartment->pool, false);
RegisterAllocation *alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
if (!alloc)
return NULL;
@ -853,7 +853,7 @@ FrameState::discardForJoin(RegisterAllocation *&alloc, uint32 stackDepth)
* This shows up for loop entries which are not reachable from the
* loop head, and for exception, switch target and trap safe points.
*/
alloc = ArenaNew<RegisterAllocation>(cx->compartment->pool, false);
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
if (!alloc)
return false;
}

View File

@ -157,7 +157,7 @@ LoopState::init(jsbytecode *head, Jump entry, jsbytecode *entryTarget)
RegisterAllocation *&alloc = outerAnalysis->getAllocation(head);
JS_ASSERT(!alloc);
alloc = ArenaNew<RegisterAllocation>(cx->compartment->pool, true);
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(true);
if (!alloc)
return false;

View File

@ -50,7 +50,6 @@
#include <locale.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsarena.h"
#include "jsutil.h"
#include "jsprf.h"
#include "jswrapper.h"
@ -1955,16 +1954,13 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
static JSBool
Notes(JSContext *cx, uintN argc, jsval *vp)
{
uintN i;
JSScript *script;
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
jsval *argv = JS_ARGV(cx, vp);
for (i = 0; i < argc; i++) {
script = ValueToScript(cx, argv[i]);
for (uintN i = 0; i < argc; i++) {
JSScript *script = ValueToScript(cx, argv[i]);
if (!script)
continue;
@ -1972,7 +1968,6 @@ Notes(JSContext *cx, uintN argc, jsval *vp)
}
JSString *str = JS_NewStringCopyZ(cx, sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!str)
return JS_FALSE;
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
@ -2113,9 +2108,9 @@ DisassembleToString(JSContext *cx, uintN argc, jsval *vp)
if (!p.parse(cx))
return false;
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter *sp = &sprinter;
bool ok = true;
@ -2139,7 +2134,6 @@ DisassembleToString(JSContext *cx, uintN argc, jsval *vp)
}
JSString *str = ok ? JS_NewStringCopyZ(cx, sprinter.base) : NULL;
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!str)
return false;
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
@ -2153,9 +2147,9 @@ Disassemble(JSContext *cx, uintN argc, jsval *vp)
if (!p.parse(cx))
return false;
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter *sp = &sprinter;
bool ok = true;
@ -2180,7 +2174,6 @@ Disassemble(JSContext *cx, uintN argc, jsval *vp)
if (ok)
fprintf(stdout, "%s\n", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return ok;
}
@ -2216,13 +2209,12 @@ DisassFile(JSContext *cx, uintN argc, jsval *vp)
if (!script)
return false;
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
bool ok = DisassembleScript(cx, script, NULL, p.lines, p.recursive, &sprinter);
if (ok)
fprintf(stdout, "%s\n", sprinter.base);
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!ok)
return false;
@ -2266,18 +2258,17 @@ DisassWithSrc(JSContext *cx, uintN argc, jsval *vp)
pc = script->code;
end = pc + script->length;
void *mark = JS_ARENA_MARK(&cx->tempPool);
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
Sprinter *sp = &sprinter;
INIT_SPRINTER(cx, sp, &cx->tempPool, 0);
INIT_SPRINTER(cx, sp, &cx->tempLifoAlloc(), 0);
/* burn the leading lines */
line2 = JS_PCToLineNumber(cx, script, pc);
for (line1 = 0; line1 < line2 - 1; line1++) {
char *tmp = fgets(linebuf, LINE_BUF_LEN, file);
if (!tmp) {
JS_ReportError(cx, "failed to read %s fully",
script->filename);
JS_ReportError(cx, "failed to read %s fully", script->filename);
ok = JS_FALSE;
goto bail;
}
@ -2318,7 +2309,6 @@ DisassWithSrc(JSContext *cx, uintN argc, jsval *vp)
}
bail:
JS_ARENA_RELEASE(&cx->tempPool, mark);
fclose(file);
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);

View File

@ -183,6 +183,7 @@ struct DebugOnly
DebugOnly& operator=(const T&) { return *this; }
void operator++(int) {}
void operator--(int) {}
bool operator<(const T&) { return false; }
#endif
/*