--- a/js/src/jsatom.cpp 2012-12-15 17:25:40.399796882 +0100 +++ b/js/src/jsatom.cpp 2012-12-15 17:29:58.911808809 +0100 @@ -431,17 +431,17 @@ js_SweepAtomState(JSContext *cx) e.removeFront(); } } bool AtomIsInterned(JSContext *cx, JSAtom *atom) { /* We treat static strings as interned because they're never collected. */ - if (StaticStrings::isStatic(atom)) + if (cx->runtime->staticStrings.isStatic(atom)) return true; AutoLockAtomsCompartment lock(cx); AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(atom); if (!p) return false; return p->isTagged(); @@ -520,17 +520,17 @@ Atomize(JSContext *cx, const jschar **pc } JSAtom * js_AtomizeString(JSContext *cx, JSString *str, InternBehavior ib) { if (str->isAtom()) { JSAtom &atom = str->asAtom(); /* N.B. static atoms are effectively always interned. */ - if (ib != InternAtom || js::StaticStrings::isStatic(&atom)) + if (ib != InternAtom || cx->runtime->staticStrings.isStatic(&atom)) return &atom; /* Here we have to check whether the atom is already interned. */ AutoLockAtomsCompartment lock(cx); AtomSet &atoms = cx->runtime->atomState.atoms; AtomSet::Ptr p = atoms.lookup(AtomHasher::Lookup(&atom)); JS_ASSERT(p); /* Non-static atom must exist in atom state set. */ --- a/js/src/jsgcchunk.cpp 2012-12-15 17:25:40.391796882 +0100 +++ b/js/src/jsgcchunk.cpp 2012-12-15 17:29:35.951807750 +0100 @@ -30,16 +30,17 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ***** END LICENSE BLOCK ***** */ #include #include "jstypes.h" #include "jsstdint.h" #include "jsgcchunk.h" +#include "yarr/PageBlock.h" /* for pageSize() */ #ifdef XP_WIN # include "jswin.h" # ifdef _MSC_VER # pragma warning( disable: 4267 4996 4146 ) # endif @@ -299,16 +300,24 @@ UnmapPages(void *addr, size_t size) JS_ALWAYS_TRUE(munmap((caddr_t) addr, size) == 0); #else JS_ALWAYS_TRUE(munmap(addr, size) == 0); #endif } #endif +static size_t +RoundUpToPage(size_t size) +{ + size_t page = pageSize(); + size_t mask = page - 1; + return (size + mask) & ~mask; +} + namespace js { namespace gc { static inline void * FindChunkStart(void *p) { jsuword addr = reinterpret_cast(p); addr = (addr + ChunkMask) & ~ChunkMask; @@ -402,11 +411,27 @@ DecommitMemory(void *addr, size_t size) JS_ASSERT(uintptr_t(addr) % 4096UL == 0); int result = madvise(addr, size, MADV_DONTNEED); return result != -1; } #else # error "No CommitMemory defined on this platform." #endif +void * +MapMemory(size_t size) +{ +#ifdef JS_GC_HAS_MAP_ALIGN + return MapAlignedPages(RoundUpToPage(size), pageSize()); +#else + return MapPages(NULL, RoundUpToPage(size)); +#endif /* !JS_GC_HAS_MAP_ALIGN */ +} + +void +UnmapMemory(void *addr, size_t size) +{ + UnmapPages(addr, RoundUpToPage(size)); +} + } /* namespace gc */ } /* namespace js */ --- a/js/src/jsgcchunk.h 2012-12-15 17:25:40.399796882 +0100 +++ b/js/src/jsgcchunk.h 2012-12-15 17:29:42.271808041 +0100 @@ -57,12 +57,18 @@ void FreeChunk(void *p); bool CommitMemory(void *addr, size_t size); bool DecommitMemory(void *addr, size_t size); +void * +MapMemory(size_t size); + +void +UnmapMemory(void *addr, size_t size); + } /* namespace gc */ } /* namespace js */ #endif /* jsgchunk_h__ */ --- a/js/src/vm/String.cpp 2012-12-15 17:25:40.415796883 +0100 +++ b/js/src/vm/String.cpp 2012-12-15 17:30:19.299809750 +0100 @@ -39,16 +39,17 @@ * ***** END LICENSE BLOCK ***** */ #include "mozilla/RangedPtr.h" #include "jsgcmark.h" #include "String.h" #include "String-inl.h" +#include "jsgcchunk.h" using namespace mozilla; using namespace js; bool JSString::isShort() const { bool is_short = (getAllocKind() == gc::FINALIZE_SHORT_STRING); @@ -393,57 +394,104 @@ JSFlatString::isIndex(uint32 *indexp) co * the lowercase letters, and the next 26 are the uppercase letters. */ #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \ (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \ (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \ StaticStrings::INVALID_SMALL_CHAR) #define R TO_SMALL_CHAR +#ifdef JS_MMEM_FOR_STATIC_STRINGS +const StaticStrings::SmallChar StaticStrings::toSmallCharConstImage[] = { R7(0) }; +#else /* JS_MMEM_FOR_STATIC_STRINGS */ const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) }; +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ #undef R +StaticStrings::~StaticStrings() +{ +#ifdef JS_MMEM_FOR_STATIC_STRINGS + if (initialized) { + gc::UnmapMemory(mappedMem, sizeof(*mappedMem)); + } +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ +} + bool StaticStrings::init(JSContext *cx) { - SwitchToCompartment sc(cx, cx->runtime->atomsCompartment); + if (!initialized) { - for (uint32 i = 0; i < UNIT_STATIC_LIMIT; i++) { - jschar buffer[] = { i, 0x00 }; - JSFixedString *s = js_NewStringCopyN(cx, buffer, 1); - if (!s) - return false; - unitStaticTable[i] = s->morphAtomizedStringIntoAtom(); - } +#ifdef JS_MMEM_FOR_STATIC_STRINGS - for (uint32 i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) { - jschar buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), 0x00 }; - JSFixedString *s = js_NewStringCopyN(cx, buffer, 2); - if (!s) + mappedMem = reinterpret_cast(gc::MapMemory(sizeof(*mappedMem))); + if (!mappedMem) return false; - length2StaticTable[i] = s->morphAtomizedStringIntoAtom(); - } + + length2StaticTable = mappedMem->length2StaticTable; + intStaticTable = mappedMem->intStaticTable; + unitStaticTable = mappedMem->unitStaticTable; + toSmallChar = mappedMem->toSmallChar; + + for (uint32 i = 0; + i < sizeof(toSmallCharConstImage)/sizeof(toSmallCharConstImage[0]); + i++) + mappedMem->toSmallChar[i] = toSmallCharConstImage[i]; + +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ + + SwitchToCompartment sc(cx, cx->runtime->atomsCompartment); + + for (uint32 i = 0; i < UNIT_STATIC_LIMIT; i++) { + jschar buffer[] = { i, 0x00 }; + JSFixedString *s = js_NewStringCopyN(cx, buffer, 1); + if (!s) { +#ifdef JS_MMEM_FOR_STATIC_STRINGS + gc::UnmapMemory(mappedMem, sizeof(*mappedMem)); +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ + return false; + } + unitStaticTable[i] = s->morphAtomizedStringIntoAtom(); + } - for (uint32 i = 0; i < INT_STATIC_LIMIT; i++) { - if (i < 10) { - intStaticTable[i] = unitStaticTable[i + '0']; - } else if (i < 100) { - size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) + - TO_SMALL_CHAR((i % 10) + '0'); - intStaticTable[i] = length2StaticTable[index]; - } else { - jschar buffer[] = { (i / 100) + '0', ((i / 10) % 10) + '0', (i % 10) + '0', 0x00 }; - JSFixedString *s = js_NewStringCopyN(cx, buffer, 3); - if (!s) + for (uint32 i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) { + jschar buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), 0x00 }; + JSFixedString *s = js_NewStringCopyN(cx, buffer, 2); + if (!s) { +#ifdef JS_MMEM_FOR_STATIC_STRINGS + gc::UnmapMemory(mappedMem, sizeof(*mappedMem)); +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ return false; - intStaticTable[i] = s->morphAtomizedStringIntoAtom(); + } + length2StaticTable[i] = s->morphAtomizedStringIntoAtom(); } + + for (uint32 i = 0; i < INT_STATIC_LIMIT; i++) { + if (i < 10) { + intStaticTable[i] = unitStaticTable[i + '0']; + } else if (i < 100) { + size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) + + TO_SMALL_CHAR((i % 10) + '0'); + intStaticTable[i] = length2StaticTable[index]; + } else { + jschar buffer[] = { (i / 100) + '0', ((i / 10) % 10) + '0', (i % 10) + '0', 0x00 }; + JSFixedString *s = js_NewStringCopyN(cx, buffer, 3); + if (!s) { +#ifdef JS_MMEM_FOR_STATIC_STRINGS + gc::UnmapMemory(mappedMem, sizeof(*mappedMem)); +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ + return false; + } + intStaticTable[i] = s->morphAtomizedStringIntoAtom(); + } + } + + initialized = true; } - initialized = true; return true; } void StaticStrings::trace(JSTracer *trc) { if (!initialized) return; --- a/js/src/vm/String.h 2012-12-15 17:25:40.415796883 +0100 +++ b/js/src/vm/String.h 2012-12-15 17:30:26.695810091 +0100 @@ -41,16 +41,26 @@ #ifndef String_h_ #define String_h_ #include "mozilla/Util.h" #include "jsapi.h" #include "jscell.h" +#if defined(__ia64__) +/* + * Don't use static strings in static memory on ia64 since the compiler may + * put it out of the acceptable 47-bit jsval pointer range. Use dynamic memory + * which is mapped to 47-bit jsval pointer range instead. Enabling the JIT + * isn't possible with that. + */ +# define JS_MMEM_FOR_STATIC_STRINGS +#endif + class JSString; class JSDependentString; class JSUndependedString; class JSExtensibleString; class JSExternalString; class JSLinearString; class JSFixedString; class JSRope; @@ -702,53 +712,89 @@ class StaticStrings bool initialized; /* Bigger chars cannot be in a length-2 string. */ static const size_t SMALL_CHAR_LIMIT = 128U; static const size_t NUM_SMALL_CHARS = 64U; static const size_t INT_STATIC_LIMIT = 256U; + public: + /* We keep these public for the methodjit. */ + static const size_t UNIT_STATIC_LIMIT = 256U; + + private: + typedef uint8 SmallChar; + static const SmallChar INVALID_SMALL_CHAR = -1; + +#ifdef JS_MMEM_FOR_STATIC_STRINGS + + private: + /* The array has NUM_SMALL_CHARS * NUM_SMALL_CHARS elements. */ + JSAtom **length2StaticTable; + /* The array has INT_STATIC_LIMIT elements. */ + JSAtom **intStaticTable; + public: + /* We keep these public for the methodjit. */ + /* The array has UNIT_STATIC_LIMIT elements. */ + JSAtom **unitStaticTable; + private: + static const SmallChar toSmallCharConstImage[]; + /* The array has SMALL_CHAR_LIMIT elements. */ + const SmallChar *toSmallChar; + + struct MappedTables + { + JSAtom *length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS]; + JSAtom *intStaticTable[INT_STATIC_LIMIT]; + JSAtom *unitStaticTable[UNIT_STATIC_LIMIT]; + SmallChar toSmallChar[SMALL_CHAR_LIMIT]; + }; + + MappedTables *mappedMem; + +#else /* JS_MMEM_FOR_STATIC_STRINGS */ + + private: JSAtom *length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS]; JSAtom *intStaticTable[INT_STATIC_LIMIT]; - public: /* We keep these public for the methodjit. */ - static const size_t UNIT_STATIC_LIMIT = 256U; JSAtom *unitStaticTable[UNIT_STATIC_LIMIT]; + private: + static const SmallChar toSmallChar[]; + +#endif /* JS_MMEM_FOR_STATIC_STRINGS */ + public: StaticStrings() : initialized(false) {} + ~StaticStrings(); bool init(JSContext *cx); void trace(JSTracer *trc); static inline bool hasUint(uint32 u); inline JSAtom *getUint(uint32 u); static inline bool hasInt(int32 i); inline JSAtom *getInt(jsint i); static inline bool hasUnit(jschar c); JSAtom *getUnit(jschar c); /* May not return atom, returns null on (reported) failure. */ inline JSLinearString *getUnitStringForElement(JSContext *cx, JSString *str, size_t index); - static bool isStatic(JSAtom *atom); + bool isStatic(JSAtom *atom); /* Return null if no static atom exists for the given (chars, length). */ inline JSAtom *lookup(const jschar *chars, size_t length); private: - typedef uint8 SmallChar; - static const SmallChar INVALID_SMALL_CHAR = -1; - - static inline bool fitsInSmallChar(jschar c); - - static const SmallChar toSmallChar[]; + inline bool fitsInSmallChar(jschar c); JSAtom *getLength2(jschar c1, jschar c2); JSAtom *getLength2(uint32 i); }; /* * Represents an atomized string which does not contain an index (that is, an * unsigned 32-bit value). Thus for any PropertyName propname, Signed-off-by: Stephan Schreiber