Merge.
Merge.
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -617,33 +617,35 @@ js_GetCallObject(JSContext *cx, JSStackF
#endif
/*
* Create the call object, using the frame's enclosing scope as its
* parent, and link the call to its stack frame. For a named function
* expression Call's parent points to an environment object holding
* function's name.
*/
- JSObject *parent = fp->scopeChain;
JSAtom *lambdaName = (fp->fun->flags & JSFUN_LAMBDA) ? fp->fun->atom : NULL;
if (lambdaName) {
- parent = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
- parent, 0);
- if (!parent)
+ JSObject *env = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL,
+ fp->scopeChain, 0);
+ if (!env)
return JS_FALSE;
+
+ /* Root env. */
+ fp->scopeChain = env;
}
- callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0);
+ callobj = js_NewObject(cx, &js_CallClass, NULL, fp->scopeChain, 0);
if (!callobj)
return NULL;
JS_SetPrivate(cx, callobj, fp);
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee));
STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(fp->callee));
if (lambdaName &&
- !js_DefineNativeProperty(cx, parent, ATOM_TO_JSID(lambdaName),
+ !js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName),
OBJECT_TO_JSVAL(fp->callee), NULL, NULL,
JSPROP_PERMANENT | JSPROP_READONLY,
0, 0, NULL)) {
return JS_FALSE;
}
fp->callobj = callobj;
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -311,11 +311,22 @@ js_CompareAndSwap(jsword *w, jsword ov,
static inline JSBool
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
{
return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE;
}
#endif
+static inline void
+js_AtomicSetMask(jsword *w, jsword mask)
+{
+ jsword ov, nv;
+
+ do {
+ ov = *w;
+ nv = ov | mask;
+ } while (!js_CompareAndSwap(w, ov, nv));
+}
+
JS_END_EXTERN_C
#endif /* jslock_h___ */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2930,17 +2930,17 @@ js_FinalizeStringRT(JSRuntime *rt, JSStr
* Assume that the finalizer for the permanently interned
* string knows how to deal with null context.
*/
finalizer(cx, str);
}
}
}
}
- if (valid)
+ if (valid && JSSTRING_IS_DEFLATED(str))
js_PurgeDeflatedStringCache(rt, str);
}
JS_FRIEND_API(const char *)
js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun)
{
JSString *str;
@@ -3449,16 +3449,17 @@ js_SetStringBytes(JSContext *cx, JSStrin
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;
#ifdef DEBUG
if (ok)
rt->deflatedStringCacheBytes += length;
#endif
+ JSSTRING_SET_DEFLATED(str);
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
return ok;
}
const char *
js_GetStringBytes(JSContext *cx, JSString *str)
{
@@ -3503,16 +3504,17 @@ js_GetStringBytes(JSContext *cx, JSStrin
} else {
bytes = js_DeflateString(cx, JSSTRING_CHARS(str),
JSSTRING_LENGTH(str));
if (bytes) {
if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
#ifdef DEBUG
rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str);
#endif
+ JSSTRING_SET_DEFLATED(str);
} else {
if (cx)
JS_free(cx, bytes);
else
free(bytes);
bytes = NULL;
}
}
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -103,18 +103,19 @@ struct JSString {
* JSSTRFLAG_PREFIX should be used only if JSSTRFLAG_DEPENDENT is set and
* JSSTRFLAG_MUTABLE should be used only if the string is flat.
* JSSTRFLAG_ATOMIZED is used only with the flat immutable strings.
*/
#define JSSTRFLAG_DEPENDENT JSSTRING_BIT(JS_BITS_PER_WORD - 1)
#define JSSTRFLAG_PREFIX JSSTRING_BIT(JS_BITS_PER_WORD - 2)
#define JSSTRFLAG_MUTABLE JSSTRFLAG_PREFIX
#define JSSTRFLAG_ATOMIZED JSSTRING_BIT(JS_BITS_PER_WORD - 3)
+#define JSSTRFLAG_DEFLATED JSSTRING_BIT(JS_BITS_PER_WORD - 4)
-#define JSSTRING_LENGTH_BITS (JS_BITS_PER_WORD - 3)
+#define JSSTRING_LENGTH_BITS (JS_BITS_PER_WORD - 4)
#define JSSTRING_LENGTH_MASK JSSTRING_BITMASK(JSSTRING_LENGTH_BITS)
/* Universal JSString type inquiry and accessor macros. */
#define JSSTRING_BIT(n) ((size_t)1 << (n))
#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1)
#define JSSTRING_HAS_FLAG(str,flg) ((str)->length & (flg))
#define JSSTRING_IS_DEPENDENT(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_DEPENDENT)
#define JSSTRING_IS_FLAT(str) (!JSSTRING_IS_DEPENDENT(str))
@@ -127,16 +128,23 @@ struct JSString {
#define JSSTRING_CHARS(str) (JSSTRING_IS_DEPENDENT(str) \
? JSSTRDEP_CHARS(str) \
: JSFLATSTR_CHARS(str))
#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \
? JSSTRDEP_LENGTH(str) \
: JSFLATSTR_LENGTH(str))
+JS_STATIC_ASSERT(sizeof(size_t) == sizeof(jsword));
+
+#define JSSTRING_IS_DEFLATED(str) ((str)->length & JSSTRFLAG_DEFLATED)
+
+#define JSSTRING_SET_DEFLATED(str) js_AtomicSetMask((jsword*)&(str)->length, \
+ JSSTRFLAG_DEFLATED);
+
#define JSSTRING_CHARS_AND_LENGTH(str, chars_, length_) \
((void)(JSSTRING_IS_DEPENDENT(str) \
? ((length_) = JSSTRDEP_LENGTH(str), \
(chars_) = JSSTRDEP_CHARS(str)) \
: ((length_) = JSFLATSTR_LENGTH(str), \
(chars_) = JSFLATSTR_CHARS(str))))
#define JSSTRING_CHARS_AND_END(str, chars_, end) \
@@ -177,18 +185,20 @@ struct JSString {
*
* On the other hand, if the thread sees that the flag is unset, it could be
* seeing a stale value when another thread has just atomized the string and
* set the flag. But this can lead only to an extra call to js_AtomizeString.
* This function would find that the string was already hashed and return it
* with the atomized bit set.
*/
#define JSFLATSTR_SET_ATOMIZED(str) \
- ((void)(JS_ASSERT(JSSTRING_IS_FLAT(str) && !JSSTRING_IS_MUTABLE(str)), \
- (str)->length |= JSSTRFLAG_ATOMIZED))
+ JS_BEGIN_MACRO \
+ JS_ASSERT(JSSTRING_IS_FLAT(str) && !JSSTRING_IS_MUTABLE(str)); \
+ js_AtomicSetMask((jsword*) &(str)->length, JSSTRFLAG_ATOMIZED); \
+ JS_END_MACRO
#define JSFLATSTR_SET_MUTABLE(str) \
((void)(JS_ASSERT(JSSTRING_IS_FLAT(str) && !JSSTRING_IS_ATOMIZED(str)), \
(str)->length |= JSSTRFLAG_MUTABLE))
#define JSFLATSTR_CLEAR_MUTABLE(str) \
((void)(JS_ASSERT(JSSTRING_IS_FLAT(str)), \
JSSTRING_HAS_FLAG(str, JSSTRFLAG_MUTABLE) && \