Bug 612150 - Eliminating JS_GetFunctionName. r=mrbkap

This commit is contained in:
Igor Bukanov 2010-11-24 17:56:43 +01:00
parent 01067dbf04
commit 3717953163
16 changed files with 96 additions and 323 deletions

View File

@ -273,7 +273,7 @@ struct JSDValue
intN nref;
JSCList props;
JSString* string;
const char* funName;
JSString* funName;
const char* className;
JSDValue* proto;
JSDValue* parent;
@ -460,7 +460,7 @@ jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript);
extern const char*
jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
extern const char*
extern JSString*
jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript);
extern uintN
@ -724,7 +724,7 @@ jsd_GetThisForStackFrame(JSDContext* jsdc,
JSDThreadState* jsdthreadstate,
JSDStackFrameInfo* jsdframe);
extern const char*
extern JSString*
jsd_GetNameForStackFrame(JSDContext* jsdc,
JSDThreadState* jsdthreadstate,
JSDStackFrameInfo* jsdframe);
@ -969,7 +969,7 @@ jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval);
extern JSString*
jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
extern const char*
extern JSString*
jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval);
/**************************************************/

View File

@ -197,22 +197,29 @@ static void
_dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
{
const char* name;
const char* fun;
JSString* fun;
uintN base;
uintN extent;
char Buf[256];
size_t n;
name = jsd_GetScriptFilename(jsdc, jsdscript);
fun = jsd_GetScriptFunctionName(jsdc, jsdscript);
base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
sprintf( Buf, "%sscript=%08X, %s, %s, %d-%d\n",
leadingtext,
(unsigned) jsdscript->script,
name ? name : "no URL",
fun ? fun : "no fun",
base, base + extent - 1 );
n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
leadingtext, (unsigned) jsdscript->script,
name ? name : "no URL"));
if (n + 1 < sizeof(Buf)) {
if (fun) {
n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
} else {
n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
Buf[sizeof(Buf) - 1] = '\0';
}
if (n + 1 < sizeof(Buf))
snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
}
OutputDebugString( Buf );
}
@ -488,12 +495,15 @@ jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
return jsdscript->url;
}
const char*
JSString*
jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
{
JSString* str;
if( ! jsdscript->function )
return NULL;
return JS_GetFunctionName(jsdscript->function);
str = JS_GetFunctionId(jsdscript->function);
return str ? str : JS_GetEmptyString(jsdc->jsrt);
}
uintN

View File

@ -356,12 +356,12 @@ jsd_GetThisForStackFrame(JSDContext* jsdc,
return jsdval;
}
const char*
JSString*
jsd_GetNameForStackFrame(JSDContext* jsdc,
JSDThreadState* jsdthreadstate,
JSDStackFrameInfo* jsdframe)
{
const char *rv = NULL;
JSString *rv = NULL;
JSD_LOCK_THREADSTATES(jsdc);
@ -370,7 +370,7 @@ jsd_GetNameForStackFrame(JSDContext* jsdc,
JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
jsdframe->fp);
if (fun)
rv = JS_GetFunctionName (fun);
rv = JS_GetFunctionId (fun);
}
JSD_UNLOCK_THREADSTATES(jsdc);

View File

@ -69,7 +69,7 @@ _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSStackFrame *fp,
JSDScript* jsdscript = NULL;
JSScript * script;
static indent = 0;
const char* funName = NULL;
JSString* funName = NULL;
script = JS_GetFrameScript(cx, fp);
if(script)
@ -80,27 +80,29 @@ _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSStackFrame *fp,
if(jsdscript)
funName = JSD_GetScriptFunctionName(jsdc, jsdscript);
}
if(!funName)
funName = "TOP_LEVEL";
if(before)
printf("%sentering ", _indentSpaces(indent++));
else
printf("%sleaving ", _indentSpaces(--indent));
if (!funName)
printf("TOP_LEVEL");
else
JS_FileEscapedString(stdout, funName, 0);
if(before)
{
jsval thisVal;
printf("%sentering %s %s this: ",
_indentSpaces(indent++),
funName,
JS_IsConstructorFrame(cx, fp) ? "constructing":"");
printf("%s this: ", JS_IsConstructorFrame(cx, fp) ? "constructing":"");
if (JS_GetFrameThis(cx, fp, &thisVal))
printf("0x%0llx\n", (JSUword) thisVal);
printf("0x%0llx", (JSUword) thisVal);
else
puts("<unavailable>");
}
else
{
printf("%sleaving %s\n", _indentSpaces(--indent), funName);
}
printf("\n");
JS_ASSERT(indent >= 0);
}
#endif

View File

@ -246,7 +246,7 @@ jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
return jsdval->string;
}
const char*
JSString*
jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
{
JSContext* cx = jsdc->dumbContext;
@ -272,7 +272,9 @@ jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
JS_EndRequest(cx);
if(!fun)
return NULL;
jsdval->funName = JS_GetFunctionName(fun);
jsdval->funName = JS_GetFunctionId(fun);
if (!jsdval->funName)
jsdval->funName = JS_GetEmptyString(jsdc->jsrt);
}
return jsdval->funName;
}

View File

@ -953,6 +953,23 @@ jsdProperty::GetVarArgSlot(PRUint32 *_rval)
/* Scripts */
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
static NS_IMETHODIMP
AssignToJSString(nsACString *x, JSString *str)
{
if (!str) {
x->SetLength(0);
return NS_OK;
}
size_t length = JS_GetStringEncodingLength(NULL, str);
if (length == size_t(-1))
return NS_ERROR_FAILURE;
x->SetLength(PRUint32(length));
if (x->Length() != PRUint32(length))
return NS_ERROR_OUT_OF_MEMORY;
JS_EncodeStringToBuffer(str, x->BeginWriting(), length);
return NS_OK;
}
jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
mTag(0),
mCx(aCx),
@ -971,8 +988,12 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
* gets destroyed. */
JSD_LockScriptSubsystem(mCx);
mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
mFunctionName =
new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
mFunctionName = new nsCString();
if (mFunctionName) {
JSString *str = JSD_GetScriptFunctionName(mCx, mScript);
if (str)
AssignToJSString(mFunctionName, str);
}
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
@ -1844,7 +1865,11 @@ NS_IMETHODIMP
jsdStackFrame::GetFunctionName(nsACString &_rval)
{
ASSERT_VALID_EPHEMERAL;
_rval.Assign(JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo));
JSString *str = JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo);
if (str)
return AssignToJSString(&_rval, str);
_rval.Assign("anonymous");
return NS_OK;
}
@ -2172,8 +2197,7 @@ NS_IMETHODIMP
jsdValue::GetJsFunctionName(nsACString &_rval)
{
ASSERT_VALID_EPHEMERAL;
_rval.Assign(JSD_GetValueFunctionName(mCx, mValue));
return NS_OK;
return AssignToJSString(&_rval, JSD_GetValueFunctionName(mCx, mValue));
}
NS_IMETHODIMP

View File

@ -302,7 +302,7 @@ JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
return jsd_GetScriptFilename(jsdc, jsdscript);
}
JSD_PUBLIC_API(const char*)
JSD_PUBLIC_API(JSString *)
JSD_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
{
JSD_ASSERT_VALID_CONTEXT(jsdc);
@ -741,7 +741,7 @@ JSD_GetThisForStackFrame(JSDContext* jsdc,
return jsd_GetThisForStackFrame(jsdc, jsdthreadstate, jsdframe);
}
JSD_PUBLIC_API(const char*)
JSD_PUBLIC_API(JSString *)
JSD_GetNameForStackFrame(JSDContext* jsdc,
JSDThreadState* jsdthreadstate,
JSDStackFrameInfo* jsdframe)
@ -1108,7 +1108,7 @@ JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
return jsd_GetValueString(jsdc, jsdval);
}
JSD_PUBLIC_API(const char*)
JSD_PUBLIC_API(JSString *)
JSD_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
{
JSD_ASSERT_VALID_CONTEXT(jsdc);

View File

@ -429,9 +429,10 @@ extern JSD_PUBLIC_API(const char*)
JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
/*
* Get the function name associated with this script (NULL if not a function)
* Get the function name associated with this script (NULL if not a function).
* If the function does not have a name the result is an empty string.
*/
extern JSD_PUBLIC_API(const char*)
extern JSD_PUBLIC_API(JSString *)
JSD_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript);
/*
@ -955,7 +956,7 @@ JSD_GetThisForStackFrame(JSDContext* jsdc,
* Get the name of the function executing in this stack frame. Especially useful
* for native frames (without script objects.)
*/
extern JSD_PUBLIC_API(const char*)
extern JSD_PUBLIC_API(JSString *)
JSD_GetNameForStackFrame(JSDContext* jsdc,
JSDThreadState* jsdthreadstate,
JSDStackFrameInfo* jsdframe);
@ -1288,7 +1289,7 @@ JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
* Return name of function IFF JSDValue represents a function.
* *** new for version 1.1 ****
*/
extern JSD_PUBLIC_API(const char*)
extern JSD_PUBLIC_API(JSString *)
JSD_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval);
/**************************************************/

View File

@ -202,6 +202,13 @@ JS_GetEmptyStringValue(JSContext *cx)
return STRING_TO_JSVAL(cx->runtime->emptyString);
}
JS_PUBLIC_API(JSString *)
JS_GetEmptyString(JSRuntime *rt)
{
JS_ASSERT(rt->state == JSRTS_UP);
return rt->emptyString;
}
static JSBool
TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
{
@ -634,10 +641,6 @@ JSRuntime::init(uint32 maxbytes)
return false;
#endif
deflatedStringCache = new js::DeflatedStringCache();
if (!deflatedStringCache || !deflatedStringCache->init())
return false;
wrapObjectCallback = js::TransparentObjectWrapper;
#ifdef JS_THREADSAFE
@ -683,11 +686,6 @@ JSRuntime::~JSRuntime()
js_FreeRuntimeScriptState(this);
js_FinishAtomState(this);
/*
* Finish the deflated string cache after the last GC and after
* calling js_FinishAtomState, which finalizes strings.
*/
delete deflatedStringCache;
#if ENABLE_YARR_JIT
delete regExpAllocator;
#endif
@ -4212,15 +4210,6 @@ JS_GetFunctionObject(JSFunction *fun)
return FUN_OBJECT(fun);
}
JS_PUBLIC_API(const char *)
JS_GetFunctionName(JSFunction *fun)
{
if (!fun->atom)
return js_anonymous_str;
const char *byte = js_GetStringBytes(fun->atom);
return byte ? byte : "";
}
JS_PUBLIC_API(JSString *)
JS_GetFunctionId(JSFunction *fun)
{

View File

@ -545,6 +545,9 @@ JS_GetPositiveInfinityValue(JSContext *cx);
extern JS_PUBLIC_API(jsval)
JS_GetEmptyStringValue(JSContext *cx);
extern JS_PUBLIC_API(JSString *)
JS_GetEmptyString(JSRuntime *rt);
/*
* Format is a string of the following characters (spaces are insignificant),
* specifying the tabulated type conversions:
@ -2339,22 +2342,11 @@ JS_NewFunctionById(JSContext *cx, JSNative call, uintN nargs, uintN flags,
extern JS_PUBLIC_API(JSObject *)
JS_GetFunctionObject(JSFunction *fun);
/*
* Deprecated, useful only for diagnostics. Use JS_GetFunctionId instead for
* anonymous vs. "anonymous" disambiguation and Unicode fidelity.
*/
extern JS_PUBLIC_API(const char *)
JS_GetFunctionName(JSFunction *fun);
/*
* Return the function's identifier as a JSString, or null if fun is unnamed.
* The returned string lives as long as fun, so you don't need to root a saved
* reference to it if fun is well-connected or rooted, and provided you bound
* the use of the saved reference by fun's lifetime.
*
* Prefer JS_GetFunctionId over JS_GetFunctionName because it returns null for
* truly anonymous functions, and because it doesn't chop to ISO-Latin-1 chars
* from UTF-16-ish jschars.
*/
extern JS_PUBLIC_API(JSString *)
JS_GetFunctionId(JSFunction *fun);

View File

@ -1369,8 +1369,6 @@ struct JSRuntime {
js::Value negativeInfinityValue;
js::Value positiveInfinityValue;
js::DeflatedStringCache *deflatedStringCache;
JSString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */

View File

@ -2203,12 +2203,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
}
TIMESTAMP(sweepObjectEnd);
/*
* We sweep the deflated cache before we finalize the strings so the
* cache can safely use js_IsAboutToBeFinalized..
*/
rt->deflatedStringCache->sweep(cx);
for (JSCompartment **comp = rt->compartments.begin(); comp != rt->compartments.end(); comp++) {
FinalizeArenaList<JSShortString>(*comp, cx, FINALIZE_SHORT_STRING);
FinalizeArenaList<JSString>(*comp, cx, FINALIZE_STRING);

View File

@ -82,7 +82,7 @@ Probes::FunctionLineNumber(JSContext *cx, const JSFunction *fun)
*
* jsval returned
* -------------------
* STRING -> char *
* STRING -> void *
* INT -> int
* DOUBLE -> double *
* BOOLEAN -> int
@ -109,9 +109,6 @@ jsprobes_jsvaltovoid(JSContext *cx, const js::Value &argval)
if (argval.isBoolean())
return (void *)argval.toBoolean();
if (argval.isString())
return (void *)js_GetStringBytes(cx, argval.toString());
if (argval.isNumber()) {
if (argval.isInt32())
return (void *)argval.toInt32();

View File

@ -164,8 +164,6 @@ template <class T,
class AllocPolicy = ContextAllocPolicy>
class HashSet;
class DeflatedStringCache;
class PropertyCache;
struct PropertyCacheEntry;

View File

@ -3294,12 +3294,6 @@ __attribute__ ((aligned (8)))
#undef R
#define R(c) FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3f), 0x00
const char JSString::deflatedLength2StringTable[] = { R12(0) };
#undef R
/*
* Declare int strings. Only int strings from 100 to 255 actually have to be
* generated, since the rest are either unit strings or length-2 strings. To
@ -3350,16 +3344,6 @@ const JSString *const JSString::intStringTable[] = { R8(0) };
#pragma pack(pop)
#endif
#define R(c) ((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00
const char JSString::deflatedIntStringTable[] = {
R7(100), /* 100 through 227 */
R4(100 + (1 << 7)), /* 228 through 243 */
R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
};
#undef R
#undef R2
#undef R4
#undef R6
@ -3370,18 +3354,6 @@ const char JSString::deflatedIntStringTable[] = {
#undef R3
#undef R7
/* Static table for common UTF8 encoding */
#define U8(c) char(((c) >> 6) | 0xc0), char(((c) & 0x3f) | 0x80), 0
#define U(c) U8(c), U8(c+1), U8(c+2), U8(c+3), U8(c+4), U8(c+5), U8(c+6), U8(c+7)
const char JSString::deflatedUnitStringTable[] = {
U(0x80), U(0x88), U(0x90), U(0x98), U(0xa0), U(0xa8), U(0xb0), U(0xb8),
U(0xc0), U(0xc8), U(0xd0), U(0xd8), U(0xe0), U(0xe8), U(0xf0), U(0xf8)
};
#undef U
#undef U8
JSBool
js_String(JSContext *cx, uintN argc, Value *vp)
{
@ -4012,7 +3984,7 @@ js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp)
}
/*
* May be called with null cx by js_GetStringBytes, see below.
* May be called with null cx.
*/
char *
js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
@ -4057,7 +4029,7 @@ js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
}
/*
* May be called with null cx through js_GetStringBytes, see below.
* May be called with null cx through public API, see below.
*/
size_t
js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars)
@ -4300,152 +4272,6 @@ bufferTooSmall:
return JS_FALSE;
}
namespace js {
DeflatedStringCache::DeflatedStringCache()
{
#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_GetFunctionName 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 (IsAboutToBeFinalized(str)) {
char *bytes = e.front().value;
e.removeFront();
/*
* We cannot use cx->free here as bytes may come from the
* embedding that calls JS_NewString(cx, bytes, length). Those
* bytes may not be allocated via js_malloc and may not have
* space for the background free list.
*/
js_free(bytes);
}
}
JS_RELEASE_LOCK(lock);
}
char *
DeflatedStringCache::getBytes(JSString *str)
{
JS_ACQUIRE_LOCK(lock);
Map::AddPtr p = map.lookupForAdd(str);
char *bytes = p ? p->value : NULL;
JS_RELEASE_LOCK(lock);
if (bytes)
return bytes;
bytes = js_DeflateString(NULL, str->chars(), str->length());
if (!bytes)
return NULL;
/*
* In the single-threaded case we use the add method as js_DeflateString
* cannot mutate the map. In particular, it cannot run the GC that may
* delete entries from the map. But the JS_THREADSAFE version requires to
* deal with other threads adding the entries to the map.
*/
char *bytesToFree = NULL;
JSBool ok;
#ifdef JS_THREADSAFE
JS_ACQUIRE_LOCK(lock);
ok = map.relookupOrAdd(p, str, bytes);
if (ok && p->value != bytes) {
/* Some other thread has asked for str bytes .*/
JS_ASSERT(!strcmp(p->value, bytes));
bytesToFree = bytes;
bytes = p->value;
}
JS_RELEASE_LOCK(lock);
#else /* !JS_THREADSAFE */
ok = map.add(p, str, bytes);
#endif
if (!ok) {
bytesToFree = bytes;
bytes = NULL;
}
if (bytesToFree)
js_free(bytesToFree);
return bytes;
}
} /* namespace js */
const char *
js_GetStringBytes(JSAtom *atom)
{
JSString *str = ATOM_TO_STRING(atom);
if (JSString::isUnitString(str)) {
char *bytes;
#ifdef IS_LITTLE_ENDIAN
/* Unit string data is {c, 0, 0, 0} so we can just cast. */
bytes = (char *)str->chars();
#else
/* Unit string data is {0, c, 0, 0} so we can point into the middle. */
bytes = (char *)str->chars() + 1;
#endif
return ((*bytes & 0x80) && js_CStringsAreUTF8)
? JSString::deflatedUnitStringTable + ((*bytes & 0x7f) * 3)
: bytes;
}
/*
* We must burn some space on deflated int strings and length-2 strings
* to preserve static allocation (which is to say, JSRuntime independence).
*/
if (JSString::isLength2String(str))
return JSString::deflatedLength2StringTable + ((str - JSString::length2StringTable) * 3);
if (JSString::isHundredString(str)) {
/*
* We handled the 1 and 2-digit number cases already, so we know that
* str is between 100 and 255.
*/
return JSString::deflatedIntStringTable + ((str - JSString::hundredStringTable) * 4);
}
return GetGCThingRuntime(str)->deflatedStringCache->getBytes(str);
}
/*
* From java.lang.Character.java:
*

View File

@ -514,9 +514,6 @@ struct JSString {
* strings, we keep a table to map from integer to the correct string.
*/
static const JSString *const intStringTable[];
static const char deflatedIntStringTable[];
static const char deflatedUnitStringTable[];
static const char deflatedLength2StringTable[];
static JSString *unitString(jschar c);
static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
@ -1146,13 +1143,6 @@ extern JSBool
js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
size_t charsLength, 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.
*/
extern const char *
js_GetStringBytes(JSAtom *atom);
/* Export a few natives and a helper to other files in SpiderMonkey. */
extern JSBool
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv,
@ -1223,54 +1213,4 @@ FileEscapedString(FILE *fp, JSString *str, uint32 quote)
extern JSBool
js_String(JSContext *cx, uintN argc, js::Value *vp);
namespace js {
class DeflatedStringCache {
public:
DeflatedStringCache();
bool init();
~DeflatedStringCache();
void sweep(JSContext *cx);
private:
struct StringPtrHasher
{
typedef JSString *Lookup;
static HashNumber 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 HashNumber(key);
}
static bool match(JSString *s1, JSString *s2) {
return s1 == s2;
}
};
typedef HashMap<JSString *, char *, StringPtrHasher, SystemAllocPolicy> Map;
char *getBytes(JSString *str);
friend const char *
::js_GetStringBytes(JSAtom *atom);
Map map;
#ifdef JS_THREADSAFE
JSLock *lock;
#endif
};
} /* namespace js */
#endif /* jsstr_h___ */