mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 639883 - Use JSString (not JSShortString) for inline really short inline strings (r=njn)
--HG-- extra : rebase_source : 5d18f67f841864064e032836014978cf51b52f5c
This commit is contained in:
parent
53aca4319a
commit
1913b99eb0
@ -3575,28 +3575,38 @@ js_NewString(JSContext *cx, jschar *chars, size_t length)
|
||||
return JSFixedString::new_(cx, chars, length);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSShortString *
|
||||
static JS_ALWAYS_INLINE JSFixedString *
|
||||
NewShortString(JSContext *cx, const jschar *chars, size_t length)
|
||||
{
|
||||
/*
|
||||
* Don't bother trying to find a static atom; measurement shows that not
|
||||
* many get here (for one, Atomize is catching them).
|
||||
*/
|
||||
|
||||
JS_ASSERT(JSShortString::lengthFits(length));
|
||||
JSShortString *str = js_NewGCShortString(cx);
|
||||
JSInlineString *str = JSInlineString::lengthFits(length)
|
||||
? JSInlineString::new_(cx)
|
||||
: JSShortString::new_(cx);
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
jschar *storage = str->init(length);
|
||||
PodCopy(storage, chars, length);
|
||||
storage[length] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
static JSShortString *
|
||||
static JSInlineString *
|
||||
NewShortString(JSContext *cx, const char *chars, size_t length)
|
||||
{
|
||||
JS_ASSERT(JSShortString::lengthFits(length));
|
||||
JSShortString *str = js_NewGCShortString(cx);
|
||||
JSInlineString *str = JSInlineString::lengthFits(length)
|
||||
? JSInlineString::new_(cx)
|
||||
: JSShortString::new_(cx);
|
||||
if (!str)
|
||||
return NULL;
|
||||
jschar *storage = str->init(length);
|
||||
|
||||
jschar *storage = str->init(length);
|
||||
if (js_CStringsAreUTF8) {
|
||||
#ifdef DEBUG
|
||||
size_t oldLength = length;
|
||||
|
141
js/src/jsstr.h
141
js/src/jsstr.h
@ -77,8 +77,8 @@
|
||||
* property via a flat string's "extensible" property.
|
||||
*
|
||||
* - To avoid allocating small char arrays, short strings can be stored inline
|
||||
* in the string header. To increase the max size of such inline strings,
|
||||
* double-wide string headers (JSShortString) can be used.
|
||||
* in the string header (JSInlineString). To increase the max size of such
|
||||
* inline strings, extra-large string headers can be used (JSShortString).
|
||||
*
|
||||
* - To avoid comparing O(n) string equality comparison, strings can be
|
||||
* canonicalized to "atoms" (JSAtom) such that there is a single atom with a
|
||||
@ -113,11 +113,15 @@
|
||||
* |
|
||||
* JSFixedString - / may have external pointers into char array
|
||||
* | \ \
|
||||
* | \ JSExternalString - / chars stored in header
|
||||
* | \ JSExternalString - / char array memory managed by embedding
|
||||
* | \
|
||||
* | JSShortString - / chars stored in header
|
||||
* | |
|
||||
* JSAtom | - / string equality === pointer equality
|
||||
* | JSInlineString - / chars stored in header
|
||||
* | | \
|
||||
* | | JSShortString - / header is fat
|
||||
* | | |
|
||||
* JSAtom | | - / string equality === pointer equality
|
||||
* | \ | |
|
||||
* | JSInlineAtom | - / atomized JSInlineString
|
||||
* | \ |
|
||||
* | JSShortAtom - / atomized JSShortString
|
||||
* |
|
||||
@ -149,7 +153,7 @@ class JSString : public js::gc::Cell
|
||||
JSString *left; /* JSRope */
|
||||
} u1;
|
||||
union {
|
||||
jschar inlineStorage[NUM_INLINE_CHARS]; /* JSShortString */
|
||||
jschar inlineStorage[NUM_INLINE_CHARS]; /* JS(Inline|Short)String */
|
||||
struct {
|
||||
union {
|
||||
JSLinearString *base; /* JSDependentString */
|
||||
@ -187,6 +191,7 @@ class JSString : public js::gc::Cell
|
||||
* JSFlatString xx00
|
||||
* JSExtensibleString 1100
|
||||
* JSFixedString xy00 where xy != 11
|
||||
* JSInlineString 0100 and chars == inlineStorage
|
||||
* JSShortString 0100 and in FINALIZE_SHORT_STRING arena
|
||||
* JSExternalString 0100 and in FINALIZE_EXTERNAL_STRING arena
|
||||
* JSAtom x000
|
||||
@ -480,6 +485,63 @@ class JSFixedString : public JSFlatString
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSFixedString) == sizeof(JSString));
|
||||
|
||||
class JSInlineString : public JSFixedString
|
||||
{
|
||||
static const size_t MAX_INLINE_LENGTH = NUM_INLINE_CHARS - 1;
|
||||
|
||||
public:
|
||||
static inline JSInlineString *new_(JSContext *cx);
|
||||
|
||||
inline jschar *init(size_t length);
|
||||
|
||||
inline void resetLength(size_t length);
|
||||
|
||||
static bool lengthFits(size_t length) {
|
||||
return length <= MAX_INLINE_LENGTH;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSInlineString) == sizeof(JSString));
|
||||
|
||||
class JSShortString : public JSInlineString
|
||||
{
|
||||
/* This can be any value that is a multiple of sizeof(gc::FreeCell). */
|
||||
static const size_t INLINE_EXTENSION_CHARS = sizeof(JSString::Data) / sizeof(jschar);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % sizeof(js::gc::FreeCell) == 0);
|
||||
JS_STATIC_ASSERT(MAX_SHORT_LENGTH + 1 ==
|
||||
(sizeof(JSShortString) -
|
||||
offsetof(JSShortString, d.inlineStorage)) / sizeof(jschar));
|
||||
}
|
||||
|
||||
jschar inlineStorageExtension[INLINE_EXTENSION_CHARS];
|
||||
|
||||
public:
|
||||
static inline JSShortString *new_(JSContext *cx);
|
||||
|
||||
jschar *inlineStorageBeforeInit() {
|
||||
return d.inlineStorage;
|
||||
}
|
||||
|
||||
inline void initAtOffsetInBuffer(const jschar *chars, size_t length);
|
||||
|
||||
static const size_t MAX_SHORT_LENGTH = JSString::NUM_INLINE_CHARS +
|
||||
INLINE_EXTENSION_CHARS
|
||||
-1 /* null terminator */;
|
||||
|
||||
static bool lengthFits(size_t length) {
|
||||
return length <= MAX_SHORT_LENGTH;
|
||||
}
|
||||
|
||||
/* Only called by the GC for strings with the FINALIZE_EXTERNAL_STRING kind. */
|
||||
|
||||
JS_ALWAYS_INLINE void finalize(JSContext *cx);
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSShortString) == 2 * sizeof(JSString));
|
||||
|
||||
class JSExternalString : public JSFixedString
|
||||
{
|
||||
static void staticAsserts() {
|
||||
@ -520,59 +582,6 @@ class JSExternalString : public JSFixedString
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSExternalString) == sizeof(JSString));
|
||||
|
||||
class JSShortString : public JSFixedString
|
||||
{
|
||||
/* This can be any value that is a multiple of sizeof(gc::FreeCell). */
|
||||
static const size_t INLINE_EXTENSION_CHARS = sizeof(JSString::Data) / sizeof(jschar);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(INLINE_EXTENSION_CHARS % sizeof(js::gc::FreeCell) == 0);
|
||||
JS_STATIC_ASSERT(MAX_SHORT_LENGTH + 1 ==
|
||||
(sizeof(JSShortString) -
|
||||
offsetof(JSShortString, d.inlineStorage)) / sizeof(jschar));
|
||||
}
|
||||
|
||||
jschar inlineStorageExtension[INLINE_EXTENSION_CHARS];
|
||||
|
||||
public:
|
||||
jschar *inlineStorageBeforeInit() {
|
||||
return d.inlineStorage;
|
||||
}
|
||||
|
||||
jschar *init(size_t length) {
|
||||
JS_ASSERT(lengthFits(length));
|
||||
d.u1.chars = d.inlineStorage;
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
return d.inlineStorage;
|
||||
}
|
||||
|
||||
void resetLength(size_t length) {
|
||||
JS_ASSERT(lengthFits(length));
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
}
|
||||
|
||||
void initAtOffsetInBuffer(const jschar *chars, size_t length) {
|
||||
JS_ASSERT(lengthFits(length + (chars - d.inlineStorage)));
|
||||
JS_ASSERT(chars >= d.inlineStorage && chars < d.inlineStorage + MAX_SHORT_LENGTH);
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
d.u1.chars = chars;
|
||||
}
|
||||
|
||||
static const size_t MAX_SHORT_LENGTH = JSString::NUM_INLINE_CHARS +
|
||||
INLINE_EXTENSION_CHARS
|
||||
-1 /* null terminator */;
|
||||
|
||||
static inline bool lengthFits(size_t length) {
|
||||
return length <= MAX_SHORT_LENGTH;
|
||||
}
|
||||
|
||||
/* Only called by the GC for strings with the FINALIZE_EXTERNAL_STRING kind. */
|
||||
|
||||
JS_ALWAYS_INLINE void finalize(JSContext *cx);
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSShortString) == 2 * sizeof(JSString));
|
||||
|
||||
class JSAtom : public JSFixedString
|
||||
{
|
||||
public:
|
||||
@ -637,7 +646,17 @@ class JSAtom : public JSFixedString
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString));
|
||||
|
||||
class JSShortAtom : public JSShortString /*, JSAtom */
|
||||
class JSInlineAtom : public JSInlineString /*, JSAtom */
|
||||
{
|
||||
/*
|
||||
* JSInlineAtom is not explicitly used and is only present for consistency.
|
||||
* See Atomize() for how JSInlineStrings get morphed into JSInlineAtoms.
|
||||
*/
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSInlineAtom) == sizeof(JSInlineString));
|
||||
|
||||
class JSShortAtom : public JSShortString /*, JSInlineAtom */
|
||||
{
|
||||
/*
|
||||
* JSShortAtom is not explicitly used and is only present for consistency.
|
||||
|
@ -338,6 +338,43 @@ JSFixedString::morphInternedStringIntoAtom()
|
||||
return &asAtom();
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSInlineString *
|
||||
JSInlineString::new_(JSContext *cx)
|
||||
{
|
||||
return (JSInlineString *)js_NewGCString(cx);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE jschar *
|
||||
JSInlineString::init(size_t length)
|
||||
{
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
d.u1.chars = d.inlineStorage;
|
||||
JS_ASSERT(lengthFits(length) || (isShort() && JSShortString::lengthFits(length)));
|
||||
return d.inlineStorage;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
JSInlineString::resetLength(size_t length)
|
||||
{
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
JS_ASSERT(lengthFits(length) || (isShort() && JSShortString::lengthFits(length)));
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSShortString *
|
||||
JSShortString::new_(JSContext *cx)
|
||||
{
|
||||
return js_NewGCShortString(cx);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
JSShortString::initAtOffsetInBuffer(const jschar *chars, size_t length)
|
||||
{
|
||||
JS_ASSERT(lengthFits(length + (chars - d.inlineStorage)));
|
||||
JS_ASSERT(chars >= d.inlineStorage && chars < d.inlineStorage + MAX_SHORT_LENGTH);
|
||||
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
|
||||
d.u1.chars = chars;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE void
|
||||
JSExternalString::init(const jschar *chars, size_t length, intN type)
|
||||
{
|
||||
@ -478,7 +515,13 @@ JSFlatString::finalize(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(!isShort());
|
||||
rt->stringMemoryUsed -= length() * 2;
|
||||
rt->free(const_cast<jschar *>(chars()));
|
||||
|
||||
/*
|
||||
* This check depends on the fact that 'chars' is only initialized to the
|
||||
* beginning of inlineStorage. E.g., this is not the case for short strings.
|
||||
*/
|
||||
if (chars() != d.inlineStorage)
|
||||
rt->free_(const_cast<jschar *>(chars()));
|
||||
}
|
||||
|
||||
inline void
|
||||
|
Loading…
Reference in New Issue
Block a user