mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
bug 519476 - replacing JSSTRING_DEFLATED with scanning of the deflated cache. r=jwalden,dmandelin
This commit is contained in:
parent
b84116c011
commit
e8a9de6f10
@ -565,10 +565,14 @@ JSRuntime::init(uint32 maxbytes)
|
||||
{
|
||||
if (!js_InitDtoa() ||
|
||||
!js_InitGC(this, maxbytes) ||
|
||||
!js_InitAtomState(this) ||
|
||||
!js_InitDeflatedStringCache(this)) {
|
||||
!js_InitAtomState(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
deflatedStringCache = new js::DeflatedStringCache();
|
||||
if (!deflatedStringCache || !deflatedStringCache->init())
|
||||
return false;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
gcLock = JS_NEW_LOCK();
|
||||
if (!gcLock)
|
||||
@ -629,7 +633,7 @@ JSRuntime::~JSRuntime()
|
||||
* Finish the deflated string cache after the last GC and after
|
||||
* calling js_FinishAtomState, which finalizes strings.
|
||||
*/
|
||||
js_FinishDeflatedStringCache(this);
|
||||
delete deflatedStringCache;
|
||||
js_FinishGC(this);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (gcLock)
|
||||
@ -5063,7 +5067,7 @@ JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
|
||||
}
|
||||
|
||||
/* Hand off bytes to the deflated string cache, if possible. */
|
||||
if (!js_SetStringBytes(cx, str, bytes, nbytes))
|
||||
if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
|
||||
cx->free(bytes);
|
||||
return str;
|
||||
}
|
||||
@ -5192,7 +5196,7 @@ JS_GetStringChars(JSString *str)
|
||||
if (s) {
|
||||
memcpy(s, str->dependentChars(), n * sizeof *s);
|
||||
s[n] = 0;
|
||||
str->reinitFlat(s, n);
|
||||
str->initFlat(s, n);
|
||||
} else {
|
||||
s = str->dependentChars();
|
||||
}
|
||||
|
@ -501,6 +501,7 @@ js_InitCommonAtoms(JSContext *cx)
|
||||
JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
|
||||
memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
|
||||
|
||||
cx->runtime->emptyString = ATOM_TO_STRING(state->emptyAtom);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -516,8 +517,8 @@ js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||
void
|
||||
js_FinishCommonAtoms(JSContext *cx)
|
||||
{
|
||||
cx->runtime->emptyString = NULL;
|
||||
JSAtomState *state = &cx->runtime->atomState;
|
||||
|
||||
JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL);
|
||||
#ifdef DEBUG
|
||||
memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN,
|
||||
|
@ -545,8 +545,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
ok = js_InitRuntimeScriptState(rt);
|
||||
if (ok)
|
||||
ok = js_InitRuntimeNumberState(cx);
|
||||
if (ok)
|
||||
ok = js_InitRuntimeStringState(cx);
|
||||
if (ok)
|
||||
ok = JSScope::initRuntimeState(cx);
|
||||
|
||||
@ -778,7 +776,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
|
||||
JSScope::finishRuntimeState(cx);
|
||||
js_FinishRuntimeNumberState(cx);
|
||||
js_FinishRuntimeStringState(cx);
|
||||
|
||||
/* Unpin all common atoms before final GC. */
|
||||
js_FinishCommonAtoms(cx);
|
||||
|
@ -820,13 +820,7 @@ struct JSRuntime {
|
||||
jsval negativeInfinityValue;
|
||||
jsval positiveInfinityValue;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSLock *deflatedStringCacheLock;
|
||||
#endif
|
||||
JSHashTable *deflatedStringCache;
|
||||
#ifdef DEBUG
|
||||
uint32 deflatedStringCacheBytes;
|
||||
#endif
|
||||
js::DeflatedStringCache *deflatedStringCache;
|
||||
|
||||
JSString *emptyString;
|
||||
|
||||
|
@ -2622,8 +2622,6 @@ FinalizeString(JSContext *cx, JSString *str, unsigned thingKind)
|
||||
*/
|
||||
cx->free(str->flatChars());
|
||||
}
|
||||
if (str->isDeflated())
|
||||
js_PurgeDeflatedStringCache(cx->runtime, str);
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -2643,8 +2641,6 @@ FinalizeExternalString(JSContext *cx, JSString *str, unsigned thingKind)
|
||||
JSStringFinalizeOp finalizer = str_finalizers[type];
|
||||
if (finalizer)
|
||||
finalizer(cx, str);
|
||||
if (str->isDeflated())
|
||||
js_PurgeDeflatedStringCache(cx->runtime, str);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2686,8 +2682,6 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (str->isDeflated())
|
||||
js_PurgeDeflatedStringCache(rt, str);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
@ -3195,6 +3189,13 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
FinalizeArenaList<JSXML, FinalizeXML>(cx, FINALIZE_XML, &emptyArenas);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We sweep the deflated cache before we finalize the strings so the
|
||||
* cache can safely use js_IsAboutToBeFinalized..
|
||||
*/
|
||||
rt->deflatedStringCache->sweep(cx);
|
||||
|
||||
FinalizeArenaList<JSString, FinalizeString>
|
||||
(cx, FINALIZE_STRING, &emptyArenas);
|
||||
for (unsigned i = FINALIZE_EXTERNAL_STRING0;
|
||||
|
@ -172,6 +172,8 @@ template <class T,
|
||||
class AllocPolicy = ContextAllocPolicy>
|
||||
class HashSet;
|
||||
|
||||
class DeflatedStringCache;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/* Common instantiations. */
|
||||
|
291
js/src/jsstr.cpp
291
js/src/jsstr.cpp
@ -104,7 +104,7 @@ MinimizeDependentStrings(JSString *str, int level, JSString **basep)
|
||||
} while (base->isDependent());
|
||||
}
|
||||
length = str->dependentLength();
|
||||
str->reinitDependent(base, start, length);
|
||||
str->initDependent(base, start, length);
|
||||
}
|
||||
*basep = base;
|
||||
return start;
|
||||
@ -187,7 +187,7 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
||||
|
||||
/* Morph left into a dependent string if we realloc'd its buffer. */
|
||||
if (ldep) {
|
||||
ldep->reinitDependent(str, 0, ln);
|
||||
ldep->initDependent(str, 0, ln);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
@ -219,7 +219,7 @@ js_UndependString(JSContext *cx, JSString *str)
|
||||
|
||||
js_strncpy(s, str->dependentChars(), n);
|
||||
s[n] = 0;
|
||||
str->reinitFlat(s, n);
|
||||
str->initFlat(s, n);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -3015,66 +3015,6 @@ static JSFunctionSpec string_static_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
static JSHashNumber
|
||||
js_hash_string_pointer(const void *key)
|
||||
{
|
||||
return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitRuntimeStringState(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
|
||||
rt = cx->runtime;
|
||||
rt->emptyString = ATOM_TO_STRING(rt->atomState.emptyAtom);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitDeflatedStringCache(JSRuntime *rt)
|
||||
{
|
||||
JSHashTable *cache;
|
||||
|
||||
/* Initialize string cache */
|
||||
JS_ASSERT(!rt->deflatedStringCache);
|
||||
cache = JS_NewHashTable(8, js_hash_string_pointer,
|
||||
JS_CompareValues, JS_CompareValues,
|
||||
NULL, NULL);
|
||||
if (!cache)
|
||||
return JS_FALSE;
|
||||
rt->deflatedStringCache = cache;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!rt->deflatedStringCacheLock);
|
||||
rt->deflatedStringCacheLock = JS_NEW_LOCK();
|
||||
if (!rt->deflatedStringCacheLock)
|
||||
return JS_FALSE;
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishRuntimeStringState(JSContext *cx)
|
||||
{
|
||||
cx->runtime->emptyString = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishDeflatedStringCache(JSRuntime *rt)
|
||||
{
|
||||
if (rt->deflatedStringCache) {
|
||||
JS_HashTableDestroy(rt->deflatedStringCache);
|
||||
rt->deflatedStringCache = NULL;
|
||||
}
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->deflatedStringCacheLock) {
|
||||
JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
|
||||
rt->deflatedStringCacheLock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitStringClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@ -3264,26 +3204,6 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s)
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str)
|
||||
{
|
||||
JSHashNumber hash;
|
||||
JSHashEntry *he, **hep;
|
||||
|
||||
hash = js_hash_string_pointer(str);
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
#ifdef DEBUG
|
||||
rt->deflatedStringCacheBytes -= str->length();
|
||||
#endif
|
||||
js_free(he->value);
|
||||
JS_HashTableRawRemove(rt->deflatedStringCache, hep, he);
|
||||
}
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(const char *)
|
||||
js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun)
|
||||
{
|
||||
@ -3794,42 +3714,154 @@ bufferTooSmall:
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length)
|
||||
namespace js {
|
||||
|
||||
DeflatedStringCache::DeflatedStringCache()
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSHashTable *cache;
|
||||
JSBool ok;
|
||||
JSHashNumber hash;
|
||||
JSHashEntry **hep;
|
||||
|
||||
rt = cx->runtime;
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
|
||||
cache = rt->deflatedStringCache;
|
||||
hash = js_hash_string_pointer(str);
|
||||
hep = JS_HashTableRawLookup(cache, hash, str);
|
||||
JS_ASSERT(*hep == NULL);
|
||||
ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
|
||||
if (ok) {
|
||||
str->setDeflated();
|
||||
#ifdef DEBUG
|
||||
rt->deflatedStringCacheBytes += length;
|
||||
#ifdef JS_THREADSAFE
|
||||
lock = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
DeflatedStringCache::init()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!lock);
|
||||
lock = JS_NEW_LOCK();
|
||||
if (!lock)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make room for 2K deflated strings that a typical browser session
|
||||
* creates.
|
||||
*/
|
||||
return map.init(2048);
|
||||
}
|
||||
|
||||
DeflatedStringCache::~DeflatedStringCache()
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
if (lock)
|
||||
JS_DESTROY_LOCK(lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DeflatedStringCache::sweep(JSContext *cx)
|
||||
{
|
||||
/*
|
||||
* We must take a lock even during the GC as JS_GetStringBytes() can be
|
||||
* called outside the request.
|
||||
*/
|
||||
JS_ACQUIRE_LOCK(lock);
|
||||
|
||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
||||
JSString *str = e.front().key;
|
||||
if (js_IsAboutToBeFinalized(str)) {
|
||||
char *chars = e.front().value;
|
||||
e.removeFront();
|
||||
cx->free(chars);
|
||||
}
|
||||
}
|
||||
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
JS_RELEASE_LOCK(lock);
|
||||
}
|
||||
|
||||
void
|
||||
DeflatedStringCache::remove(JSString *str)
|
||||
{
|
||||
JS_ACQUIRE_LOCK(lock);
|
||||
|
||||
Map::Ptr p = map.lookup(str);
|
||||
if (p) {
|
||||
js_free(p->value);
|
||||
map.remove(p);
|
||||
}
|
||||
|
||||
JS_RELEASE_LOCK(lock);
|
||||
}
|
||||
|
||||
bool
|
||||
DeflatedStringCache::setBytes(JSContext *cx, JSString *str, char *bytes)
|
||||
{
|
||||
JS_ACQUIRE_LOCK(lock);
|
||||
|
||||
Map::AddPtr p = map.lookupForAdd(str);
|
||||
JS_ASSERT(!p);
|
||||
bool ok = map.add(p, str, bytes);
|
||||
|
||||
JS_RELEASE_LOCK(lock);
|
||||
|
||||
if (!ok)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
char *
|
||||
DeflatedStringCache::getBytes(JSContext *cx, JSString *str)
|
||||
{
|
||||
JS_ACQUIRE_LOCK(lock);
|
||||
|
||||
char *bytes;
|
||||
do {
|
||||
Map::AddPtr p = map.lookupForAdd(str);
|
||||
if (p) {
|
||||
bytes = p->value;
|
||||
break;
|
||||
}
|
||||
#ifdef JS_THREADSAFE
|
||||
unsigned generation = map.generation();
|
||||
JS_RELEASE_LOCK(lock);
|
||||
#endif
|
||||
bytes = js_DeflateString(cx, str->chars(), str->length());
|
||||
if (!bytes)
|
||||
return NULL;
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ACQUIRE_LOCK(lock);
|
||||
if (generation != map.generation()) {
|
||||
p = map.lookupForAdd(str);
|
||||
if (p) {
|
||||
/* Some other thread has asked for str bytes .*/
|
||||
if (cx)
|
||||
cx->free(bytes);
|
||||
else
|
||||
js_free(bytes);
|
||||
bytes = p->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!map.add(p, str, bytes)) {
|
||||
JS_RELEASE_LOCK(lock);
|
||||
if (cx) {
|
||||
cx->free(bytes);
|
||||
js_ReportOutOfMemory(cx);
|
||||
} else {
|
||||
js_free(bytes);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
JS_ASSERT(bytes);
|
||||
|
||||
/* Try to catch failure to JS_ShutDown between runtime epochs. */
|
||||
JS_ASSERT_IF(!js_CStringsAreUTF8 && *bytes != (char) str->chars()[0],
|
||||
*bytes == '\0' && str->empty());
|
||||
|
||||
JS_RELEASE_LOCK(lock);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
const char *
|
||||
js_GetStringBytes(JSContext *cx, JSString *str)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
JSHashTable *cache;
|
||||
char *bytes;
|
||||
JSHashNumber hash;
|
||||
JSHashEntry *he, **hep;
|
||||
|
||||
if (JSString::isUnitString(str)) {
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
@ -3859,50 +3891,7 @@ js_GetStringBytes(JSContext *cx, JSString *str)
|
||||
rt = js_GetGCStringRuntime(str);
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!rt->deflatedStringCacheLock) {
|
||||
/*
|
||||
* Called from last GC (see js_DestroyContext), after runtime string
|
||||
* state has been finalized. We have no choice but to leak here.
|
||||
*/
|
||||
return js_DeflateString(NULL, str->chars(), str->length());
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
|
||||
cache = rt->deflatedStringCache;
|
||||
hash = js_hash_string_pointer(str);
|
||||
hep = JS_HashTableRawLookup(cache, hash, str);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
bytes = (char *) he->value;
|
||||
|
||||
/* Try to catch failure to JS_ShutDown between runtime epochs. */
|
||||
if (!js_CStringsAreUTF8) {
|
||||
JS_ASSERT_IF(*bytes != (char) str->chars()[0],
|
||||
*bytes == '\0' && str->empty());
|
||||
}
|
||||
} else {
|
||||
bytes = js_DeflateString(cx, str->chars(), str->length());
|
||||
if (bytes) {
|
||||
if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
|
||||
#ifdef DEBUG
|
||||
rt->deflatedStringCacheBytes += str->length();
|
||||
#endif
|
||||
str->setDeflated();
|
||||
} else {
|
||||
if (cx)
|
||||
cx->free(bytes);
|
||||
else
|
||||
js_free(bytes);
|
||||
bytes = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
return bytes;
|
||||
return rt->deflatedStringCache->getBytes(cx, str);
|
||||
}
|
||||
|
||||
/*
|
||||
|
112
js/src/jsstr.h
112
js/src/jsstr.h
@ -51,6 +51,7 @@
|
||||
#include <ctype.h>
|
||||
#include "jspubtd.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jslock.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
@ -87,10 +88,6 @@ JS_STATIC_ASSERT(JS_BITS_PER_WORD >= 32);
|
||||
* A flat string with the ATOMIZED flag means that the string is hashed as
|
||||
* an atom. This flag is used to avoid re-hashing the already-atomized string.
|
||||
*
|
||||
* Any string with the DEFLATED flag means that the string has an entry in the
|
||||
* deflated string cache. The GC uses this flag to optimize string finalization
|
||||
* and avoid an expensive cache lookup for strings that were never deflated.
|
||||
*
|
||||
* When the DEPENDENT flag is set, the string depends on characters of another
|
||||
* string strongly referenced by the mBase field. The base member may point to
|
||||
* another dependent string if chars() has not been called yet.
|
||||
@ -124,7 +121,6 @@ struct JSString {
|
||||
static const size_t DEPENDENT = JSSTRING_BIT(1);
|
||||
static const size_t MUTABLE = JSSTRING_BIT(2);
|
||||
static const size_t ATOMIZED = JSSTRING_BIT(3);
|
||||
static const size_t DEFLATED = JSSTRING_BIT(4);
|
||||
|
||||
inline bool hasFlag(size_t flag) const {
|
||||
return (mFlags & flag) != 0;
|
||||
@ -145,14 +141,6 @@ struct JSString {
|
||||
return !isDependent();
|
||||
}
|
||||
|
||||
inline bool isDeflated() const {
|
||||
return hasFlag(DEFLATED);
|
||||
}
|
||||
|
||||
inline void setDeflated() {
|
||||
JS_ATOMIC_SET_MASK(&mFlags, DEFLATED);
|
||||
}
|
||||
|
||||
inline bool isMutable() const {
|
||||
return !isDependent() && hasFlag(MUTABLE);
|
||||
}
|
||||
@ -201,18 +189,6 @@ struct JSString {
|
||||
return length();
|
||||
}
|
||||
|
||||
/*
|
||||
* Special flat string initializer that preserves the DEFLATED flag.
|
||||
* Use this method when reinitializing an existing string which may be
|
||||
* hashed to its deflated bytes. Newborn strings must use initFlat.
|
||||
*/
|
||||
void reinitFlat(jschar *chars, size_t length) {
|
||||
mLength = length;
|
||||
mOffset = 0;
|
||||
mFlags = mFlags & DEFLATED;
|
||||
mChars = chars;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods to manipulate atomized and mutable flags of flat strings. It is
|
||||
* safe to use these without extra locking due to the following properties:
|
||||
@ -264,15 +240,6 @@ struct JSString {
|
||||
mBase = bstr;
|
||||
}
|
||||
|
||||
/* See JSString::reinitFlat. */
|
||||
inline void reinitDependent(JSString *bstr, size_t off, size_t len) {
|
||||
JS_ASSERT(len <= MAX_LENGTH);
|
||||
mLength = len;
|
||||
mOffset = off;
|
||||
mFlags = DEPENDENT | (mFlags & DEFLATED);
|
||||
mBase = bstr;
|
||||
}
|
||||
|
||||
inline JSString *dependentBase() const {
|
||||
JS_ASSERT(isDependent());
|
||||
return mBase;
|
||||
@ -503,19 +470,6 @@ JS_ISSPACE(jschar c)
|
||||
#define JS7_UNHEX(c) (uintN)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
|
||||
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
|
||||
|
||||
/* Initialize per-runtime string state for the first context in the runtime. */
|
||||
extern JSBool
|
||||
js_InitRuntimeStringState(JSContext *cx);
|
||||
|
||||
extern JSBool
|
||||
js_InitDeflatedStringCache(JSRuntime *rt);
|
||||
|
||||
extern void
|
||||
js_FinishRuntimeStringState(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_FinishDeflatedStringCache(JSRuntime *rt);
|
||||
|
||||
/* Initialize the String class, returning its prototype object. */
|
||||
extern JSClass js_StringClass;
|
||||
|
||||
@ -686,13 +640,6 @@ extern JSBool
|
||||
js_DeflateStringToBuffer(JSContext *cx, const jschar *chars,
|
||||
size_t charsLength, char *bytes, size_t *length);
|
||||
|
||||
/*
|
||||
* Associate bytes with str in the deflated string cache, returning true on
|
||||
* successful association, false on out of memory.
|
||||
*/
|
||||
extern JSBool
|
||||
js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length);
|
||||
|
||||
/*
|
||||
* Find or create a deflated string cache entry for str that contains its
|
||||
* characters chopped from Unicode code points into bytes.
|
||||
@ -700,10 +647,6 @@ js_SetStringBytes(JSContext *cx, JSString *str, char *bytes, size_t length);
|
||||
extern const char *
|
||||
js_GetStringBytes(JSContext *cx, JSString *str);
|
||||
|
||||
/* Remove a deflated string cache entry associated with str if any. */
|
||||
extern void
|
||||
js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str);
|
||||
|
||||
/* Export a few natives and a helper to other files in SpiderMonkey. */
|
||||
extern JSBool
|
||||
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
@ -750,4 +693,57 @@ js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
namespace js {
|
||||
|
||||
class DeflatedStringCache {
|
||||
public:
|
||||
DeflatedStringCache();
|
||||
bool init();
|
||||
~DeflatedStringCache();
|
||||
|
||||
void sweep(JSContext *cx);
|
||||
void remove(JSString *str);
|
||||
bool setBytes(JSContext *cx, JSString *str, char *bytes);
|
||||
|
||||
private:
|
||||
struct StringPtrHasher
|
||||
{
|
||||
typedef JSString *Lookup;
|
||||
|
||||
static uint32 hash(JSString *str) {
|
||||
/*
|
||||
* We hash only GC-allocated Strings. They are aligned on
|
||||
* sizeof(JSString) boundary so we can improve hashing by stripping
|
||||
* initial zeros.
|
||||
*/
|
||||
const jsuword ALIGN_LOG = tl::FloorLog2<sizeof(JSString)>::result;
|
||||
JS_STATIC_ASSERT(sizeof(JSString) == (size_t(1) << ALIGN_LOG));
|
||||
|
||||
jsuword ptr = reinterpret_cast<jsuword>(str);
|
||||
jsuword key = ptr >> ALIGN_LOG;
|
||||
JS_ASSERT((key << ALIGN_LOG) == ptr);
|
||||
return uint32(key);
|
||||
}
|
||||
|
||||
static bool match(JSString *s1, JSString *s2) {
|
||||
return s1 == s2;
|
||||
}
|
||||
};
|
||||
|
||||
typedef HashMap<JSString *, char *, StringPtrHasher, SystemAllocPolicy> Map;
|
||||
|
||||
/* cx is NULL when the caller is JS_GetStringBytes(JSString *). */
|
||||
char *getBytes(JSContext *cx, JSString *str);
|
||||
|
||||
friend const char *
|
||||
::js_GetStringBytes(JSContext *cx, JSString *str);
|
||||
|
||||
Map map;
|
||||
#ifdef JS_THREADSAFE
|
||||
JSLock *lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsstr_h___ */
|
||||
|
@ -7495,7 +7495,7 @@ js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
|
||||
* Reallocating str (because we know it has no other references)
|
||||
* requires purging any deflated string cached for it.
|
||||
*/
|
||||
js_PurgeDeflatedStringCache(cx->runtime, str);
|
||||
cx->runtime->deflatedStringCache->remove(str);
|
||||
}
|
||||
|
||||
str2->getCharsAndLength(chars2, len2);
|
||||
|
Loading…
Reference in New Issue
Block a user