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

Generated by: LCOV version 1.7