LCOV - app.info - js/src/vm/String.cpp

LCOV - code coverage report
| Current view: | directory - js/src/vm - String.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 236 | 172 | 72.9 %
| Date: | 2012-04-07 | Functions: | 18 | 12 | 66.7 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=79 ft=cpp:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is SpiderMonkey JavaScript engine.
          18                 :  *
          19                 :  * The Initial Developer of the Original Code is
          20                 :  * Mozilla Corporation.
          21                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          22                 :  * the Initial Developer. All Rights Reserved.
          23                 :  *
          24                 :  * Contributor(s):
          25                 :  *   Luke Wagner <luke@mozilla.com>
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : #include "mozilla/RangedPtr.h"
          42                 :
          43                 : #include "jsgcmark.h"
          44                 :
          45                 : #include "String.h"
          46                 : #include "String-inl.h"
          47                 :
          48                 : #include "jsobjinlines.h"
          49                 :
          50                 : using namespace mozilla;
          51                 : using namespace js;
          52                 :
          53                 : bool
          54        86260536 : JSString::isShort() const
          55                 : {
          56        86260536 :     bool is_short = (getAllocKind() == gc::FINALIZE_SHORT_STRING);
          57        86260536 :     JS_ASSERT_IF(is_short, isFlat());
          58        86260536 :     return is_short;
          59                 : }
          60                 :
          61                 : bool
          62          365303 : JSString::isFixed() const
          63                 : {
          64          365303 :     return isFlat() && !isExtensible();
          65                 : }
          66                 :
          67                 : bool
          68               0 : JSString::isInline() const
          69                 : {
          70               0 :     return isFixed() && (d.u1.chars == d.inlineStorage || isShort());
          71                 : }
          72                 :
          73                 : bool
          74            2000 : JSString::isExternal() const
          75                 : {
          76            2000 :     bool is_external = (getAllocKind() == gc::FINALIZE_EXTERNAL_STRING);
          77            2000 :     JS_ASSERT_IF(is_external, isFixed());
          78            2000 :     return is_external;
          79                 : }
          80                 :
          81                 : size_t
          82               0 : JSString::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf)
          83                 : {
          84                 :     /* JSRope: do nothing, we'll count all children chars when we hit the leaf strings. */
          85               0 :     if (isRope())
          86               0 :         return 0;
          87                 :
          88               0 :     JS_ASSERT(isLinear());
          89                 :
          90                 :     /* JSDependentString: do nothing, we'll count the chars when we hit the base string. */
          91               0 :     if (isDependent())
          92               0 :         return 0;
          93                 :
          94               0 :     JS_ASSERT(isFlat());
          95                 :
          96                 :     /* JSExtensibleString: count the full capacity, not just the used space. */
          97               0 :     if (isExtensible()) {
          98               0 :         JSExtensibleString &extensible = asExtensible();
          99               0 :         return mallocSizeOf(extensible.chars());
         100                 :     }
         101                 :
         102               0 :     JS_ASSERT(isFixed());
         103                 :
         104                 :     /* JSExternalString: don't count, the chars could be stored anywhere. */
         105               0 :     if (isExternal())
         106               0 :         return 0;
         107                 :
         108                 :     /* JSInlineString, JSShortString, JSInlineAtom, JSShortAtom: the chars are inline. */
         109               0 :     if (isInline())
         110               0 :         return 0;
         111                 :
         112                 :     /* JSAtom, JSFixedString: count the chars. +1 for the null char. */
         113               0 :     JSFixedString &fixed = asFixed();
         114               0 :     return mallocSizeOf(fixed.chars());
         115                 : }
         116                 :
         117                 : #ifdef DEBUG
         118                 : void
         119               0 : JSString::dump()
         120                 : {
         121               0 :     if (const jschar *chars = getChars(NULL)) {
         122                 :         fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
         123               0 :                 (void *) this, (void *) chars);
         124                 :
         125                 :         extern void DumpChars(const jschar *s, size_t n);
         126               0 :         DumpChars(chars, length());
         127                 :     } else {
         128               0 :         fprintf(stderr, "(oom in JSString::dump)");
         129                 :     }
         130               0 :     fputc('\n', stderr);
         131               0 : }
         132                 :
         133                 : bool
         134               0 : JSString::equals(const char *s)
         135                 : {
         136               0 :     const jschar *c = getChars(NULL);
         137               0 :     if (!c) {
         138               0 :         fprintf(stderr, "OOM in JSString::equals!\n");
         139               0 :         return false;
         140                 :     }
         141               0 :     while (*c && *s) {
         142               0 :         if (*c != *s)
         143               0 :             return false;
         144               0 :         c++;
         145               0 :         s++;
         146                 :     }
         147               0 :     return *c == *s;
         148                 : }
         149                 : #endif /* DEBUG */
         150                 :
         151                 : static JS_ALWAYS_INLINE bool
         152          381930 : AllocChars(JSContext *maybecx, size_t length, jschar **chars, size_t *capacity)
         153                 : {
         154                 :     /*
         155                 :      * String length doesn't include the null char, so include it here before
         156                 :      * doubling. Adding the null char after doubling would interact poorly with
         157                 :      * round-up malloc schemes.
         158                 :      */
         159          381930 :     size_t numChars = length + 1;
         160                 :
         161                 :     /*
         162                 :      * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
         163                 :      * next power of 2. This is similar to what we do with arrays; see
         164                 :      * JSObject::ensureDenseArrayElements.
         165                 :      */
         166                 :     static const size_t DOUBLING_MAX = 1024 * 1024;
         167          381930 :     numChars = numChars > DOUBLING_MAX ? numChars + (numChars / 8) : RoundUpPow2(numChars);
         168                 :
         169                 :     /* Like length, capacity does not include the null char, so take it out. */
         170          381930 :     *capacity = numChars - 1;
         171                 :
         172                 :     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
         173          381930 :     size_t bytes = numChars * sizeof(jschar);
         174          381930 :     *chars = (jschar *)(maybecx ? maybecx->malloc_(bytes) : OffTheBooks::malloc_(bytes));
         175          381930 :     return *chars != NULL;
         176                 : }
         177                 :
         178                 : template<JSRope::UsingBarrier b>
         179                 : JSFlatString *
         180          472101 : JSRope::flattenInternal(JSContext *maybecx)
         181                 : {
         182                 :     /*
         183                 :      * Perform a depth-first dag traversal, splatting each node's characters
         184                 :      * into a contiguous buffer. Visit each rope node three times:
         185                 :      *   1. record position in the buffer and recurse into left child;
         186                 :      *   2. recurse into the right child;
         187                 :      *   3. transform the node into a dependent string.
         188                 :      * To avoid maintaining a stack, tree nodes are mutated to indicate how many
         189                 :      * times they have been visited. Since ropes can be dags, a node may be
         190                 :      * encountered multiple times during traversal. However, step 3 above leaves
         191                 :      * a valid dependent string, so everything works out. This algorithm is
         192                 :      * homomorphic to marking code.
         193                 :      *
         194                 :      * While ropes avoid all sorts of quadratic cases with string
         195                 :      * concatenation, they can't help when ropes are immediately flattened.
         196                 :      * One idiomatic case that we'd like to keep linear (and has traditionally
         197                 :      * been linear in SM and other JS engines) is:
         198                 :      *
         199                 :      *   while (...) {
         200                 :      *     s += ...
         201                 :      *     s.flatten
         202                 :      *   }
         203                 :      *
         204                 :      * To do this, when the buffer for a to-be-flattened rope is allocated, the
         205                 :      * allocation size is rounded up. Then, if the resulting flat string is the
         206                 :      * left-hand side of a new rope that gets flattened and there is enough
         207                 :      * capacity, the rope is flattened into the same buffer, thereby avoiding
         208                 :      * copying the left-hand side. Clearing the 'extensible' bit turns off this
         209                 :      * optimization. This is necessary, e.g., when the JSAPI hands out the raw
         210                 :      * null-terminated char array of a flat string.
         211                 :      *
         212                 :      * N.B. This optimization can create chains of dependent strings.
         213                 :      */
         214          472101 :     const size_t wholeLength = length();
         215                 :     size_t wholeCapacity;
         216                 :     jschar *wholeChars;
         217          472101 :     JSString *str = this;
         218                 :     jschar *pos;
         219                 :
         220          472101 :     if (this->leftChild()->isExtensible()) {
         221           90504 :         JSExtensibleString &left = this->leftChild()->asExtensible();
         222           90504 :         size_t capacity = left.capacity();
         223           90504 :         if (capacity >= wholeLength) {
         224                 :             if (b == WithIncrementalBarrier) {
         225               0 :                 JSString::writeBarrierPre(d.u1.left);
         226               0 :                 JSString::writeBarrierPre(d.s.u2.right);
         227                 :             }
         228                 :
         229           90171 :             wholeCapacity = capacity;
         230           90171 :             wholeChars = const_cast<jschar *>(left.chars());
         231           90171 :             size_t bits = left.d.lengthAndFlags;
         232           90171 :             pos = wholeChars + (bits >> LENGTH_SHIFT);
         233           90171 :             left.d.lengthAndFlags = bits ^ (EXTENSIBLE_FLAGS | DEPENDENT_BIT);
         234           90171 :             left.d.s.u2.base = (JSLinearString *)this;  /* will be true on exit */
         235           90171 :             JSString::writeBarrierPost(left.d.s.u2.base, &left.d.s.u2.base);
         236           90171 :             goto visit_right_child;
         237                 :         }
         238                 :     }
         239                 :
         240          381930 :     if (!AllocChars(maybecx, wholeLength, &wholeChars, &wholeCapacity))
         241               0 :         return NULL;
         242                 :
         243          381930 :     pos = wholeChars;
         244                 :     first_visit_node: {
         245                 :         if (b == WithIncrementalBarrier) {
         246               7 :             JSString::writeBarrierPre(str->d.u1.left);
         247               7 :             JSString::writeBarrierPre(str->d.s.u2.right);
         248                 :         }
         249                 :
         250         4174368 :         JSString &left = *str->d.u1.left;
         251         4174368 :         str->d.u1.chars = pos;
         252         4174368 :         if (left.isRope()) {
         253         3277989 :             left.d.s.u3.parent = str;          /* Return to this when 'left' done, */
         254         3277989 :             left.d.lengthAndFlags = 0x200;     /* but goto visit_right_child. */
         255         3277989 :             str = &left;
         256         3277989 :             goto first_visit_node;
         257                 :         }
         258          896379 :         size_t len = left.length();
         259          896379 :         PodCopy(pos, left.d.u1.chars, len);
         260          896379 :         pos += len;
         261                 :     }
         262                 :     visit_right_child: {
         263         4264539 :         JSString &right = *str->d.s.u2.right;
         264         4264539 :         if (right.isRope()) {
         265          514449 :             right.d.s.u3.parent = str;         /* Return to this node when 'right' done, */
         266          514449 :             right.d.lengthAndFlags = 0x300;    /* but goto finish_node. */
         267          514449 :             str = &right;
         268          514449 :             goto first_visit_node;
         269                 :         }
         270         3750090 :         size_t len = right.length();
         271         3750090 :         PodCopy(pos, right.d.u1.chars, len);
         272         3750090 :         pos += len;
         273                 :     }
         274                 :     finish_node: {
         275         4264539 :         if (str == this) {
         276          472101 :             JS_ASSERT(pos == wholeChars + wholeLength);
         277          472101 :             *pos = '\0';
         278          472101 :             str->d.lengthAndFlags = buildLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS);
         279          472101 :             str->d.u1.chars = wholeChars;
         280          472101 :             str->d.s.u2.capacity = wholeCapacity;
         281          472101 :             return &this->asFlat();
         282                 :         }
         283         3792438 :         size_t progress = str->d.lengthAndFlags;
         284         3792438 :         str->d.lengthAndFlags = buildLengthAndFlags(pos - str->d.u1.chars, DEPENDENT_BIT);
         285         3792438 :         str->d.s.u2.base = (JSLinearString *)this;       /* will be true on exit */
         286         3792438 :         JSString::writeBarrierPost(str->d.s.u2.base, &str->d.s.u2.base);
         287         3792438 :         str = str->d.s.u3.parent;
         288         3792438 :         if (progress == 0x200)
         289         3277989 :             goto visit_right_child;
         290          514449 :         JS_ASSERT(progress == 0x300);
         291          514449 :         goto finish_node;
         292                 :     }
         293                 : }
         294                 :
         295                 : JSFlatString *
         296          472101 : JSRope::flatten(JSContext *maybecx)
         297                 : {
         298                 : #if JSGC_INCREMENTAL
         299          472101 :     if (compartment()->needsBarrier())
         300               7 :         return flattenInternal<WithIncrementalBarrier>(maybecx);
         301                 :     else
         302          472094 :         return flattenInternal<NoBarrier>(maybecx);
         303                 : #else
         304                 :     return flattenInternal<NoBarrier>(maybecx);
         305                 : #endif
         306                 : }
         307                 :
         308                 : JSString * JS_FASTCALL
         309        19919230 : js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
         310                 : {
         311        19919230 :     JS_ASSERT_IF(!left->isAtom(), left->compartment() == cx->compartment);
         312        19919230 :     JS_ASSERT_IF(!right->isAtom(), right->compartment() == cx->compartment);
         313                 :
         314        19919230 :     size_t leftLen = left->length();
         315        19919230 :     if (leftLen == 0)
         316          135738 :         return right;
         317                 :
         318        19783492 :     size_t rightLen = right->length();
         319        19783492 :     if (rightLen == 0)
         320            6642 :         return left;
         321                 :
         322        19776850 :     size_t wholeLength = leftLen + rightLen;
         323        19776850 :     if (!JSString::validateLength(cx, wholeLength))
         324              18 :         return NULL;
         325                 :
         326        19776832 :     if (JSShortString::lengthFits(wholeLength)) {
         327         1138411 :         JSShortString *str = js_NewGCShortString(cx);
         328         1138411 :         if (!str)
         329               0 :             return NULL;
         330         1138411 :         const jschar *leftChars = left->getChars(cx);
         331         1138411 :         if (!leftChars)
         332               0 :             return NULL;
         333         1138411 :         const jschar *rightChars = right->getChars(cx);
         334         1138411 :         if (!rightChars)
         335               0 :             return NULL;
         336                 :
         337         1138411 :         jschar *buf = str->init(wholeLength);
         338         1138411 :         PodCopy(buf, leftChars, leftLen);
         339         1138411 :         PodCopy(buf + leftLen, rightChars, rightLen);
         340         1138411 :         buf[wholeLength] = 0;
         341         1138411 :         return str;
         342                 :     }
         343                 :
         344        18638421 :     return JSRope::new_(cx, left, right, wholeLength);
         345                 : }
         346                 :
         347                 : JSFixedString *
         348               0 : JSDependentString::undepend(JSContext *cx)
         349                 : {
         350               0 :     JS_ASSERT(JSString::isDependent());
         351                 :
         352                 :     /*
         353                 :      * We destroy the base() pointer in undepend, so we need a pre-barrier. We
         354                 :      * don't need a post-barrier because there aren't any outgoing pointers
         355                 :      * afterwards.
         356                 :      */
         357               0 :     JSString::writeBarrierPre(base());
         358                 :
         359               0 :     size_t n = length();
         360               0 :     size_t size = (n + 1) * sizeof(jschar);
         361               0 :     jschar *s = (jschar *) cx->malloc_(size);
         362               0 :     if (!s)
         363               0 :         return NULL;
         364                 :
         365               0 :     PodCopy(s, chars(), n);
         366               0 :     s[n] = 0;
         367                 :
         368               0 :     d.lengthAndFlags = buildLengthAndFlags(n, FIXED_FLAGS);
         369               0 :     d.u1.chars = s;
         370                 :
         371               0 :     return &this->asFixed();
         372                 : }
         373                 :
         374                 : bool
         375        23608947 : JSFlatString::isIndex(uint32_t *indexp) const
         376                 : {
         377        23608947 :     const jschar *s = charsZ();
         378        23608947 :     jschar ch = *s;
         379                 :
         380        23608947 :     if (!JS7_ISDEC(ch))
         381        23401045 :         return false;
         382                 :
         383          207902 :     size_t n = length();
         384          207902 :     if (n > UINT32_CHAR_BUFFER_LENGTH)
         385              55 :         return false;
         386                 :
         387                 :     /*
         388                 :      * Make sure to account for the '\0' at the end of characters, dereferenced
         389                 :      * in the loop below.
         390                 :      */
         391          207847 :     RangedPtr<const jschar> cp(s, n + 1);
         392          207847 :     const RangedPtr<const jschar> end(s + n, s, n + 1);
         393                 :
         394          207847 :     uint32_t index = JS7_UNDEC(*cp++);
         395          207847 :     uint32_t oldIndex = 0;
         396          207847 :     uint32_t c = 0;
         397                 :
         398          207847 :     if (index != 0) {
         399          837159 :         while (JS7_ISDEC(*cp)) {
         400          454841 :             oldIndex = index;
         401          454841 :             c = JS7_UNDEC(*cp);
         402          454841 :             index = 10 * index + c;
         403          454841 :             cp++;
         404                 :         }
         405                 :     }
         406                 :
         407                 :     /* It's not an element if there are characters after the number. */
         408          207847 :     if (cp != end)
         409             289 :         return false;
         410                 :
         411                 :     /*
         412                 :      * Look out for "4294967296" and larger-number strings that fit in
         413                 :      * UINT32_CHAR_BUFFER_LENGTH: only unsigned 32-bit integers shall pass.
         414                 :      */
         415          207558 :     if (oldIndex < UINT32_MAX / 10 || (oldIndex == UINT32_MAX / 10 && c <= (UINT32_MAX % 10))) {
         416          207462 :         *indexp = index;
         417          207462 :         return true;
         418                 :     }
         419                 :
         420              96 :     return false;
         421                 : }
         422                 :
         423                 : /*
         424                 :  * Set up some tools to make it easier to generate large tables. After constant
         425                 :  * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
         426                 :  * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
         427                 :  * To use this, define R appropriately, then use Rn(0) (for some value of n), then
         428                 :  * undefine R.
         429                 :  */
         430                 : #define R2(n) R(n),  R((n) + (1 << 0)),  R((n) + (2 << 0)),  R((n) + (3 << 0))
         431                 : #define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
         432                 : #define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
         433                 : #define R7(n) R6(n), R6((n) + (1 << 6))
         434                 :
         435                 : /*
         436                 :  * This is used when we generate our table of short strings, so the compiler is
         437                 :  * happier if we use |c| as few times as possible.
         438                 :  */
         439                 : #define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' :      \
         440                 :                                    (c) < 36 ? 'a' - 10 : \
         441                 :                                    'A' - 36))
         442                 :
         443                 : /*
         444                 :  * Declare length-2 strings. We only store strings where both characters are
         445                 :  * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
         446                 :  * the lowercase letters, and the next 26 are the uppercase letters.
         447                 :  */
         448                 : #define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' :              \
         449                 :                           (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 :         \
         450                 :                           (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 :         \
         451                 :                           StaticStrings::INVALID_SMALL_CHAR)
         452                 :
         453                 : #define R TO_SMALL_CHAR
         454                 : const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) };
         455                 : #undef R
         456                 :
         457                 : bool
         458           18761 : StaticStrings::init(JSContext *cx)
         459                 : {
         460           37522 :     SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
         461                 :
         462         4821577 :     for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
         463         4802816 :         jschar buffer[] = { i, 0x00 };
         464         4802816 :         JSFixedString *s = js_NewStringCopyN(cx, buffer, 1);
         465         4802816 :         if (!s)
         466               0 :             return false;
         467         4802816 :         unitStaticTable[i] = s->morphAtomizedStringIntoAtom();
         468                 :     }
         469                 :
         470        76863817 :     for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
         471        76845056 :         jschar buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), 0x00 };
         472        76845056 :         JSFixedString *s = js_NewStringCopyN(cx, buffer, 2);
         473        76845056 :         if (!s)
         474               0 :             return false;
         475        76845056 :         length2StaticTable[i] = s->morphAtomizedStringIntoAtom();
         476                 :     }
         477                 :
         478         4821577 :     for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) {
         479         4802816 :         if (i < 10) {
         480          187610 :             intStaticTable[i] = unitStaticTable[i + '0'];
         481         4615206 :         } else if (i < 100) {
         482                 :             size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) +
         483         1688490 :                 TO_SMALL_CHAR((i % 10) + '0');
         484         1688490 :             intStaticTable[i] = length2StaticTable[index];
         485                 :         } else {
         486         2926716 :             jschar buffer[] = { (i / 100) + '0', ((i / 10) % 10) + '0', (i % 10) + '0', 0x00 };
         487         2926716 :             JSFixedString *s = js_NewStringCopyN(cx, buffer, 3);
         488         2926716 :             if (!s)
         489               0 :                 return false;
         490         2926716 :             intStaticTable[i] = s->morphAtomizedStringIntoAtom();
         491                 :         }
         492                 :     }
         493                 :
         494           18761 :     return true;
         495                 : }
         496                 :
         497                 : void
         498           41836 : StaticStrings::trace(JSTracer *trc)
         499                 : {
         500                 :     /* These strings never change, so barriers are not needed. */
         501                 :
         502        10751852 :     for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
         503        10710016 :         if (unitStaticTable[i])
         504        10710016 :             MarkStringUnbarriered(trc, &unitStaticTable[i], "unit-static-string");
         505                 :     }
         506                 :
         507       171402092 :     for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
         508       171360256 :         if (length2StaticTable[i])
         509       171360256 :             MarkStringUnbarriered(trc, &length2StaticTable[i], "length2-static-string");
         510                 :     }
         511                 :
         512                 :     /* This may mark some strings more than once, but so be it. */
         513        10751852 :     for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) {
         514        10710016 :         if (intStaticTable[i])
         515        10710016 :             MarkStringUnbarriered(trc, &intStaticTable[i], "int-static-string");
         516                 :     }
         517           41836 : }
         518                 :
         519                 : bool
         520              19 : StaticStrings::isStatic(JSAtom *atom)
         521                 : {
         522              19 :     const jschar *chars = atom->chars();
         523              19 :     switch (atom->length()) {
         524                 :       case 1:
         525               2 :         return (chars[0] < UNIT_STATIC_LIMIT);
         526                 :       case 2:
         527               2 :         return (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]));
         528                 :       case 3:
         529               5 :         if ('1' <= chars[0] && chars[0] <= '9' &&
         530               2 :             '0' <= chars[1] && chars[1] <= '9' &&
         531               2 :             '0' <= chars[2] && chars[2] <= '9') {
         532               1 :             int i = (chars[0] - '0') * 100 +
         533               1 :                       (chars[1] - '0') * 10 +
         534               2 :                       (chars[2] - '0');
         535                 :
         536               1 :             return (unsigned(i) < INT_STATIC_LIMIT);
         537                 :         }
         538               0 :         return false;
         539                 :       default:
         540              14 :         return false;
         541                 :     }
         542                 : }
         543                 :
         544                 : #ifdef DEBUG
         545                 : void
         546               0 : JSAtom::dump()
         547                 : {
         548               0 :     fprintf(stderr, "JSAtom* (%p) = ", (void *) this);
         549               0 :     this->JSString::dump();
         550               0 : }
         551                 : #endif /* DEBUG */

Generated by: LCOV version 1.7