LCOV - app.info - js/src/vm/String-inl.h

LCOV - code coverage report
| Current view: | directory - js/src/vm - String-inl.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 208 | 193 | 92.8 %
| Date: | 2012-04-07 | Functions: | 38 | 37 | 97.4 %

           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                 : #ifndef String_inl_h__
          42                 : #define String_inl_h__
          43                 :
          44                 : #include "jscntxt.h"
          45                 : #include "jsgcmark.h"
          46                 : #include "jsprobes.h"
          47                 :
          48                 : #include "String.h"
          49                 :
          50                 : #include "jsgcinlines.h"
          51                 : #include "jsobjinlines.h"
          52                 : #include "gc/Barrier-inl.h"
          53                 :
          54                 : inline void
          55         2511006 : JSString::writeBarrierPre(JSString *str)
          56                 : {
          57                 : #ifdef JSGC_INCREMENTAL
          58         2511006 :     if (!str)
          59          149230 :         return;
          60                 :
          61         2361776 :     JSCompartment *comp = str->compartment();
          62         2361776 :     if (comp->needsBarrier()) {
          63              77 :         JSString *tmp = str;
          64              77 :         MarkStringUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
          65              77 :         JS_ASSERT(tmp == str);
          66                 :     }
          67                 : #endif
          68                 : }
          69                 :
          70                 : inline void
          71       120765240 : JSString::writeBarrierPost(JSString *str, void *addr)
          72                 : {
          73       120765240 : }
          74                 :
          75                 : inline bool
          76         2253934 : JSString::needWriteBarrierPre(JSCompartment *comp)
          77                 : {
          78                 : #ifdef JSGC_INCREMENTAL
          79         2253934 :     return comp->needsBarrier();
          80                 : #else
          81                 :     return false;
          82                 : #endif
          83                 : }
          84                 :
          85                 : inline void
          86        88295600 : JSString::readBarrier(JSString *str)
          87                 : {
          88                 : #ifdef JSGC_INCREMENTAL
          89        88295600 :     JSCompartment *comp = str->compartment();
          90        88295600 :     if (comp->needsBarrier()) {
          91          128068 :         JSString *tmp = str;
          92          128068 :         MarkStringUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
          93          128068 :         JS_ASSERT(tmp == str);
          94                 :     }
          95                 : #endif
          96        88295600 : }
          97                 :
          98                 : JS_ALWAYS_INLINE bool
          99        79143659 : JSString::validateLength(JSContext *cx, size_t length)
         100                 : {
         101        79143659 :     if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) {
         102              18 :         js_ReportAllocationOverflow(cx);
         103              18 :         return false;
         104                 :     }
         105                 :
         106        79143641 :     return true;
         107                 : }
         108                 :
         109                 : JS_ALWAYS_INLINE void
         110        18638421 : JSRope::init(JSString *left, JSString *right, size_t length)
         111                 : {
         112        18638421 :     d.lengthAndFlags = buildLengthAndFlags(length, ROPE_BIT);
         113        18638421 :     d.u1.left = left;
         114        18638421 :     d.s.u2.right = right;
         115        18638421 :     JSString::writeBarrierPost(d.u1.left, &d.u1.left);
         116        18638421 :     JSString::writeBarrierPost(d.s.u2.right, &d.s.u2.right);
         117        18638421 : }
         118                 :
         119                 : JS_ALWAYS_INLINE JSRope *
         120        18638421 : JSRope::new_(JSContext *cx, JSString *left, JSString *right, size_t length)
         121                 : {
         122        18638421 :     if (!validateLength(cx, length))
         123               0 :         return NULL;
         124        18638421 :     JSRope *str = (JSRope *)js_NewGCString(cx);
         125        18638421 :     if (!str)
         126               0 :         return NULL;
         127        18638421 :     str->init(left, right, length);
         128        18638421 :     return str;
         129                 : }
         130                 :
         131                 : inline void
         132            2172 : JSRope::markChildren(JSTracer *trc)
         133                 : {
         134            2172 :     js::gc::MarkStringUnbarriered(trc, &d.u1.left, "left child");
         135            2172 :     js::gc::MarkStringUnbarriered(trc, &d.s.u2.right, "right child");
         136            2172 : }
         137                 :
         138                 : JS_ALWAYS_INLINE void
         139          863144 : JSDependentString::init(JSLinearString *base, const jschar *chars, size_t length)
         140                 : {
         141          863144 :     d.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_BIT);
         142          863144 :     d.u1.chars = chars;
         143          863144 :     d.s.u2.base = base;
         144          863144 :     JSString::writeBarrierPost(d.s.u2.base, &d.s.u2.base);
         145          863144 : }
         146                 :
         147                 : JS_ALWAYS_INLINE JSDependentString *
         148          863144 : JSDependentString::new_(JSContext *cx, JSLinearString *base, const jschar *chars, size_t length)
         149                 : {
         150                 :     /* Try to avoid long chains of dependent strings. */
         151         1749571 :     while (base->isDependent())
         152           23283 :         base = base->asDependent().base();
         153                 :
         154          863144 :     JS_ASSERT(base->isFlat());
         155          863144 :     JS_ASSERT(chars >= base->chars() && chars < base->chars() + base->length());
         156          863144 :     JS_ASSERT(length <= base->length() - (chars - base->chars()));
         157                 :
         158          863144 :     JSDependentString *str = (JSDependentString *)js_NewGCString(cx);
         159          863144 :     if (!str)
         160               0 :         return NULL;
         161          863144 :     str->init(base, chars, length);
         162          863144 :     return str;
         163                 : }
         164                 :
         165                 : inline void
         166            1000 : JSDependentString::markChildren(JSTracer *trc)
         167                 : {
         168            1000 :     js::gc::MarkStringUnbarriered(trc, &d.s.u2.base, "base");
         169            1000 : }
         170                 :
         171                 : inline js::PropertyName *
         172               2 : JSFlatString::toPropertyName(JSContext *cx)
         173                 : {
         174                 : #ifdef DEBUG
         175                 :     uint32_t dummy;
         176               2 :     JS_ASSERT(!isIndex(&dummy));
         177                 : #endif
         178               2 :     if (isAtom())
         179               0 :         return asAtom().asPropertyName();
         180               2 :     JSAtom *atom = js_AtomizeString(cx, this);
         181               2 :     if (!atom)
         182               0 :         return NULL;
         183               2 :     return atom->asPropertyName();
         184                 : }
         185                 :
         186                 : JS_ALWAYS_INLINE void
         187         6777523 : JSFixedString::init(const jschar *chars, size_t length)
         188                 : {
         189         6777523 :     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
         190         6777523 :     d.u1.chars = chars;
         191         6777523 : }
         192                 :
         193                 : JS_ALWAYS_INLINE JSFixedString *
         194         6777523 : JSFixedString::new_(JSContext *cx, const jschar *chars, size_t length)
         195                 : {
         196         6777523 :     JS_ASSERT(chars[length] == jschar(0));
         197                 :
         198         6777523 :     if (!validateLength(cx, length))
         199               0 :         return NULL;
         200         6777523 :     JSFixedString *str = (JSFixedString *)js_NewGCString(cx);
         201         6777523 :     if (!str)
         202               0 :         return NULL;
         203         6777523 :     str->init(chars, length);
         204         6777523 :     return str;
         205                 : }
         206                 :
         207                 : JS_ALWAYS_INLINE JSAtom *
         208        96439813 : JSFixedString::morphAtomizedStringIntoAtom()
         209                 : {
         210        96439813 :     JS_ASSERT((d.lengthAndFlags & FLAGS_MASK) == JS_BIT(2));
         211                 :     JS_STATIC_ASSERT(NON_STATIC_ATOM == JS_BIT(3));
         212        96439813 :     d.lengthAndFlags ^= (JS_BIT(2) | JS_BIT(3));
         213        96439813 :     return &asAtom();
         214                 : }
         215                 :
         216                 : JS_ALWAYS_INLINE JSInlineString *
         217        85752816 : JSInlineString::new_(JSContext *cx)
         218                 : {
         219        85752816 :     return (JSInlineString *)js_NewGCString(cx);
         220                 : }
         221                 :
         222                 : JS_ALWAYS_INLINE jschar *
         223        93260425 : JSInlineString::init(size_t length)
         224                 : {
         225        93260425 :     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
         226        93260425 :     d.u1.chars = d.inlineStorage;
         227        93260425 :     JS_ASSERT(lengthFits(length) || (isShort() && JSShortString::lengthFits(length)));
         228        93260425 :     return d.inlineStorage;
         229                 : }
         230                 :
         231                 : JS_ALWAYS_INLINE void
         232               0 : JSInlineString::resetLength(size_t length)
         233                 : {
         234               0 :     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
         235               0 :     JS_ASSERT(lengthFits(length) || (isShort() && JSShortString::lengthFits(length)));
         236               0 : }
         237                 :
         238                 : JS_ALWAYS_INLINE JSShortString *
         239         6369198 : JSShortString::new_(JSContext *cx)
         240                 : {
         241         6369198 :     return js_NewGCShortString(cx);
         242                 : }
         243                 :
         244                 : JS_ALWAYS_INLINE void
         245        38815626 : JSShortString::initAtOffsetInBuffer(const jschar *chars, size_t length)
         246                 : {
         247        38815626 :     JS_ASSERT(lengthFits(length + (chars - d.inlineStorage)));
         248        38815626 :     JS_ASSERT(chars >= d.inlineStorage && chars < d.inlineStorage + MAX_SHORT_LENGTH);
         249        38815626 :     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
         250        38815626 :     d.u1.chars = chars;
         251        38815626 : }
         252                 :
         253                 : JS_ALWAYS_INLINE void
         254            2000 : JSExternalString::init(const jschar *chars, size_t length, const JSStringFinalizer *fin)
         255                 : {
         256            2000 :     JS_ASSERT(fin);
         257            2000 :     JS_ASSERT(fin->finalize);
         258            2000 :     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
         259            2000 :     d.u1.chars = chars;
         260            2000 :     d.s.u2.externalFinalizer = fin;
         261            2000 : }
         262                 :
         263                 : JS_ALWAYS_INLINE JSExternalString *
         264            2000 : JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length,
         265                 :                        const JSStringFinalizer *fin)
         266                 : {
         267            2000 :     JS_ASSERT(chars[length] == 0);
         268                 :
         269            2000 :     if (!validateLength(cx, length))
         270               0 :         return NULL;
         271            2000 :     JSExternalString *str = js_NewGCExternalString(cx);
         272            2000 :     if (!str)
         273               0 :         return NULL;
         274            2000 :     str->init(chars, length, fin);
         275            2000 :     cx->runtime->updateMallocCounter(cx, (length + 1) * sizeof(jschar));
         276            2000 :     return str;
         277                 : }
         278                 :
         279                 : inline bool
         280         2840412 : js::StaticStrings::fitsInSmallChar(jschar c)
         281                 : {
         282         2840412 :     return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR;
         283                 : }
         284                 :
         285                 : inline bool
         286         4387595 : js::StaticStrings::hasUnit(jschar c)
         287                 : {
         288         4387595 :     return c < UNIT_STATIC_LIMIT;
         289                 : }
         290                 :
         291                 : inline JSAtom *
         292         3080504 : js::StaticStrings::getUnit(jschar c)
         293                 : {
         294         3080504 :     JS_ASSERT(hasUnit(c));
         295         3080504 :     return unitStaticTable[c];
         296                 : }
         297                 :
         298                 : inline bool
         299          909870 : js::StaticStrings::hasUint(uint32_t u)
         300                 : {
         301          909870 :     return u < INT_STATIC_LIMIT;
         302                 : }
         303                 :
         304                 : inline JSAtom *
         305          909792 : js::StaticStrings::getUint(uint32_t u)
         306                 : {
         307          909792 :     JS_ASSERT(hasUint(u));
         308          909792 :     return intStaticTable[u];
         309                 : }
         310                 :
         311                 : inline bool
         312        40648689 : js::StaticStrings::hasInt(int32_t i)
         313                 : {
         314        40648689 :     return uint32_t(i) < INT_STATIC_LIMIT;
         315                 : }
         316                 :
         317                 : inline JSAtom *
         318          909770 : js::StaticStrings::getInt(int32_t i)
         319                 : {
         320          909770 :     JS_ASSERT(hasInt(i));
         321          909770 :     return getUint(uint32_t(i));
         322                 : }
         323                 :
         324                 : inline JSLinearString *
         325            7731 : js::StaticStrings::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
         326                 : {
         327            7731 :     JS_ASSERT(index < str->length());
         328            7731 :     const jschar *chars = str->getChars(cx);
         329            7731 :     if (!chars)
         330               0 :         return NULL;
         331            7731 :     jschar c = chars[index];
         332            7731 :     if (c < UNIT_STATIC_LIMIT)
         333            7722 :         return getUnit(c);
         334               9 :     return js_NewDependentString(cx, str, index, 1);
         335                 : }
         336                 :
         337                 : inline JSAtom *
         338          687195 : js::StaticStrings::getLength2(jschar c1, jschar c2)
         339                 : {
         340          687195 :     JS_ASSERT(fitsInSmallChar(c1));
         341          687195 :     JS_ASSERT(fitsInSmallChar(c2));
         342          687195 :     size_t index = (((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2];
         343          687195 :     return length2StaticTable[index];
         344                 : }
         345                 :
         346                 : inline JSAtom *
         347                 : js::StaticStrings::getLength2(uint32_t i)
         348                 : {
         349                 :     JS_ASSERT(i < 100);
         350                 :     return getLength2('0' + i / 10, '0' + i % 10);
         351                 : }
         352                 :
         353                 : /* Get a static atomized string for chars if possible. */
         354                 : inline JSAtom *
         355        36463296 : js::StaticStrings::lookup(const jschar *chars, size_t length)
         356                 : {
         357        36463296 :     switch (length) {
         358                 :       case 1:
         359         3528332 :         if (chars[0] < UNIT_STATIC_LIMIT)
         360         2940731 :             return getUnit(chars[0]);
         361          587601 :         return NULL;
         362                 :       case 2:
         363          778299 :         if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]))
         364          687195 :             return getLength2(chars[0], chars[1]);
         365           91104 :         return NULL;
         366                 :       case 3:
         367                 :         /*
         368                 :          * Here we know that JSString::intStringTable covers only 256 (or at least
         369                 :          * not 1000 or more) chars. We rely on order here to resolve the unit vs.
         370                 :          * int string/length-2 string atom identity issue by giving priority to unit
         371                 :          * strings for "0" through "9" and length-2 strings for "10" through "99".
         372                 :          */
         373                 :         JS_STATIC_ASSERT(INT_STATIC_LIMIT <= 999);
         374         5765628 :         if ('1' <= chars[0] && chars[0] <= '9' &&
         375          112097 :             '0' <= chars[1] && chars[1] <= '9' &&
         376          111260 :             '0' <= chars[2] && chars[2] <= '9') {
         377           55603 :             int i = (chars[0] - '0') * 100 +
         378           55603 :                       (chars[1] - '0') * 10 +
         379          111206 :                       (chars[2] - '0');
         380                 :
         381           55603 :             if (unsigned(i) < INT_STATIC_LIMIT)
         382            1747 :                 return getInt(i);
         383                 :         }
         384         5540524 :         return NULL;
         385                 :     }
         386                 :
         387        26614394 :     return NULL;
         388                 : }
         389                 :
         390                 : JS_ALWAYS_INLINE void
         391        26651446 : JSString::finalize(js::FreeOp *fop)
         392                 : {
         393                 :     /* Shorts are in a different arena. */
         394        26651446 :     JS_ASSERT(!isShort());
         395                 :
         396        26651446 :     if (isFlat())
         397         7531811 :         asFlat().finalize(fop);
         398                 :     else
         399        19119635 :         JS_ASSERT(isDependent() || isRope());
         400        26651446 : }
         401                 :
         402                 : inline void
         403         8337681 : JSFlatString::finalize(js::FreeOp *fop)
         404                 : {
         405         8337681 :     JS_ASSERT(!isShort());
         406                 :
         407                 :     /*
         408                 :      * This check depends on the fact that 'chars' is only initialized to the
         409                 :      * beginning of inlineStorage. E.g., this is not the case for short strings.
         410                 :      */
         411         8337681 :     if (chars() != d.inlineStorage)
         412         7159453 :         fop->free_(const_cast<jschar *>(chars()));
         413         8337681 : }
         414                 :
         415                 : inline void
         416        44335786 : JSShortString::finalize(js::FreeOp *fop)
         417                 : {
         418        44335786 :     JS_ASSERT(JSString::isShort());
         419        44335786 : }
         420                 :
         421                 : inline void
         422         2793319 : JSAtom::finalize(js::FreeOp *fop)
         423                 : {
         424         2793319 :     JS_ASSERT(JSString::isAtom());
         425         2793319 :     if (getAllocKind() == js::gc::FINALIZE_STRING)
         426          805870 :         JSFlatString::finalize(fop);
         427                 :     else
         428         1987449 :         JS_ASSERT(getAllocKind() == js::gc::FINALIZE_SHORT_STRING);
         429         2793319 : }
         430                 :
         431                 : inline void
         432            2000 : JSExternalString::finalize(js::FreeOp *fop)
         433                 : {
         434            2000 :     const JSStringFinalizer *fin = externalFinalizer();
         435            2000 :     fin->finalize(fin, const_cast<jschar *>(chars()));
         436            2000 : }
         437                 :
         438                 : namespace js {
         439                 :
         440                 : static JS_ALWAYS_INLINE JSFixedString *
         441        92037040 : NewShortString(JSContext *cx, const jschar *chars, size_t length)
         442                 : {
         443                 :     /*
         444                 :      * Don't bother trying to find a static atom; measurement shows that not
         445                 :      * many get here (for one, Atomize is catching them).
         446                 :      */
         447        92037040 :     JS_ASSERT(JSShortString::lengthFits(length));
         448        92037040 :     JSInlineString *str = JSInlineString::lengthFits(length)
         449                 :                           ? JSInlineString::new_(cx)
         450        92037040 :                           : JSShortString::new_(cx);
         451        92037040 :     if (!str)
         452               0 :         return NULL;
         453                 :
         454        92037040 :     jschar *storage = str->init(length);
         455        92037040 :     PodCopy(storage, chars, length);
         456        92037040 :     storage[length] = 0;
         457        92037040 :     Probes::createString(cx, str, length);
         458        92037040 :     return str;
         459                 : }
         460                 :
         461                 : } /* namespace js */
         462                 :
         463                 : #endif

Generated by: LCOV version 1.7