LCOV - code coverage report
Current view: top level - js/src/vm - String-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 152 200 76.0 %
Date: 2017-07-14 16:53:18 Functions: 36 40 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef vm_String_inl_h
       8             : #define vm_String_inl_h
       9             : 
      10             : #include "vm/String.h"
      11             : 
      12             : #include "mozilla/PodOperations.h"
      13             : #include "mozilla/Range.h"
      14             : 
      15             : #include "jscntxt.h"
      16             : #include "jscompartment.h"
      17             : 
      18             : #include "gc/Allocator.h"
      19             : #include "gc/Marking.h"
      20             : 
      21             : namespace js {
      22             : 
      23             : // Allocate a thin inline string if possible, and a fat inline string if not.
      24             : template <AllowGC allowGC, typename CharT>
      25             : static MOZ_ALWAYS_INLINE JSInlineString*
      26       69287 : AllocateInlineString(JSContext* cx, size_t len, CharT** chars)
      27             : {
      28       69287 :     MOZ_ASSERT(JSInlineString::lengthFits<CharT>(len));
      29             : 
      30       69287 :     if (JSThinInlineString::lengthFits<CharT>(len)) {
      31       51392 :         JSThinInlineString* str = JSThinInlineString::new_<allowGC>(cx);
      32       51392 :         if (!str)
      33           0 :             return nullptr;
      34       51392 :         *chars = str->init<CharT>(len);
      35       51392 :         return str;
      36             :     }
      37             : 
      38       17895 :     JSFatInlineString* str = JSFatInlineString::new_<allowGC>(cx);
      39       17895 :     if (!str)
      40           0 :         return nullptr;
      41       17895 :     *chars = str->init<CharT>(len);
      42       17895 :     return str;
      43             : }
      44             : 
      45             : // Create a thin inline string if possible, and a fat inline string if not.
      46             : template <AllowGC allowGC, typename CharT>
      47             : static MOZ_ALWAYS_INLINE JSInlineString*
      48       48432 : NewInlineString(JSContext* cx, mozilla::Range<const CharT> chars)
      49             : {
      50             :     /*
      51             :      * Don't bother trying to find a static atom; measurement shows that not
      52             :      * many get here (for one, Atomize is catching them).
      53             :      */
      54             : 
      55       48432 :     size_t len = chars.length();
      56             :     CharT* storage;
      57       48432 :     JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage);
      58       48432 :     if (!str)
      59           0 :         return nullptr;
      60             : 
      61       48432 :     mozilla::PodCopy(storage, chars.begin().get(), len);
      62       48432 :     storage[len] = 0;
      63       48432 :     return str;
      64             : }
      65             : 
      66             : // Create a thin inline string if possible, and a fat inline string if not.
      67             : template <typename CharT>
      68             : static MOZ_ALWAYS_INLINE JSInlineString*
      69         284 : NewInlineString(JSContext* cx, HandleLinearString base, size_t start, size_t length)
      70             : {
      71         284 :     MOZ_ASSERT(JSInlineString::lengthFits<CharT>(length));
      72             : 
      73             :     CharT* chars;
      74         284 :     JSInlineString* s = AllocateInlineString<CanGC>(cx, length, &chars);
      75         284 :     if (!s)
      76           0 :         return nullptr;
      77             : 
      78         568 :     JS::AutoCheckCannotGC nogc;
      79         284 :     mozilla::PodCopy(chars, base->chars<CharT>(nogc) + start, length);
      80         284 :     chars[length] = 0;
      81         284 :     return s;
      82             : }
      83             : 
      84             : static inline void
      85        9614 : StringWriteBarrierPost(JSContext* maybecx, JSString** strp)
      86             : {
      87        9614 : }
      88             : 
      89             : static inline void
      90        4842 : StringWriteBarrierPostRemove(JSContext* maybecx, JSString** strp)
      91             : {
      92        4842 : }
      93             : 
      94             : } /* namespace js */
      95             : 
      96             : MOZ_ALWAYS_INLINE bool
      97      117789 : JSString::validateLength(JSContext* maybecx, size_t length)
      98             : {
      99      117789 :     if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
     100           0 :         js::ReportAllocationOverflow(maybecx);
     101           0 :         return false;
     102             :     }
     103             : 
     104      117789 :     return true;
     105             : }
     106             : 
     107             : MOZ_ALWAYS_INLINE void
     108        3719 : JSRope::init(JSContext* cx, JSString* left, JSString* right, size_t length)
     109             : {
     110        3719 :     d.u1.length = length;
     111        3719 :     d.u1.flags = ROPE_FLAGS;
     112        3719 :     if (left->hasLatin1Chars() && right->hasLatin1Chars())
     113        3541 :         d.u1.flags |= LATIN1_CHARS_BIT;
     114        3719 :     d.s.u2.left = left;
     115        3719 :     d.s.u3.right = right;
     116        3719 :     js::StringWriteBarrierPost(cx, &d.s.u2.left);
     117        3719 :     js::StringWriteBarrierPost(cx, &d.s.u3.right);
     118        3719 : }
     119             : 
     120             : template <js::AllowGC allowGC>
     121             : MOZ_ALWAYS_INLINE JSRope*
     122        3719 : JSRope::new_(JSContext* cx,
     123             :              typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
     124             :              typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
     125             :              size_t length)
     126             : {
     127        3719 :     if (!validateLength(cx, length))
     128           0 :         return nullptr;
     129        3719 :     JSRope* str = static_cast<JSRope*>(js::Allocate<JSString, allowGC>(cx));
     130        3719 :     if (!str)
     131           0 :         return nullptr;
     132        3719 :     str->init(cx, left, right, length);
     133        3719 :     return str;
     134             : }
     135             : 
     136             : MOZ_ALWAYS_INLINE void
     137          50 : JSDependentString::init(JSContext* cx, JSLinearString* base, size_t start,
     138             :                         size_t length)
     139             : {
     140          50 :     MOZ_ASSERT(start + length <= base->length());
     141          50 :     d.u1.length = length;
     142         100 :     JS::AutoCheckCannotGC nogc;
     143          50 :     if (base->hasLatin1Chars()) {
     144          43 :         d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
     145          43 :         d.s.u2.nonInlineCharsLatin1 = base->latin1Chars(nogc) + start;
     146             :     } else {
     147           7 :         d.u1.flags = DEPENDENT_FLAGS;
     148           7 :         d.s.u2.nonInlineCharsTwoByte = base->twoByteChars(nogc) + start;
     149             :     }
     150          50 :     d.s.u3.base = base;
     151          50 :     js::StringWriteBarrierPost(cx, reinterpret_cast<JSString**>(&d.s.u3.base));
     152          50 : }
     153             : 
     154             : MOZ_ALWAYS_INLINE JSLinearString*
     155         334 : JSDependentString::new_(JSContext* cx, JSLinearString* baseArg, size_t start,
     156             :                         size_t length)
     157             : {
     158             :     /*
     159             :      * Try to avoid long chains of dependent strings. We can't avoid these
     160             :      * entirely, however, due to how ropes are flattened.
     161             :      */
     162         334 :     if (baseArg->isDependent()) {
     163          26 :         if (mozilla::Maybe<size_t> offset = baseArg->asDependent().baseOffset()) {
     164          13 :             start += *offset;
     165          13 :             baseArg = baseArg->asDependent().base();
     166             :         }
     167             :     }
     168             : 
     169         334 :     MOZ_ASSERT(start + length <= baseArg->length());
     170             : 
     171             :     /*
     172             :      * Do not create a string dependent on inline chars from another string,
     173             :      * both to avoid the awkward moving-GC hazard this introduces and because it
     174             :      * is more efficient to immediately undepend here.
     175             :      */
     176         334 :     bool useInline = baseArg->hasTwoByteChars()
     177         334 :                      ? JSInlineString::lengthFits<char16_t>(length)
     178         334 :                      : JSInlineString::lengthFits<JS::Latin1Char>(length);
     179         334 :     if (useInline) {
     180         568 :         js::RootedLinearString base(cx, baseArg);
     181         284 :         return baseArg->hasLatin1Chars()
     182        1130 :                ? js::NewInlineString<JS::Latin1Char>(cx, base, start, length)
     183         850 :                : js::NewInlineString<char16_t>(cx, base, start, length);
     184             :     }
     185             : 
     186          50 :     if (baseArg->isExternal() && !baseArg->ensureFlat(cx))
     187           0 :         return nullptr;
     188             : 
     189          50 :     JSDependentString* str = static_cast<JSDependentString*>(js::Allocate<JSString, js::NoGC>(cx));
     190          50 :     if (str) {
     191          50 :         str->init(cx, baseArg, start, length);
     192          50 :         return str;
     193             :     }
     194             : 
     195           0 :     js::RootedLinearString base(cx, baseArg);
     196             : 
     197           0 :     str = static_cast<JSDependentString*>(js::Allocate<JSString>(cx));
     198           0 :     if (!str)
     199           0 :         return nullptr;
     200           0 :     str->init(cx, base, start, length);
     201           0 :     return str;
     202             : }
     203             : 
     204             : MOZ_ALWAYS_INLINE void
     205          68 : JSFlatString::init(const char16_t* chars, size_t length)
     206             : {
     207          68 :     d.u1.length = length;
     208          68 :     d.u1.flags = FLAT_BIT;
     209          68 :     d.s.u2.nonInlineCharsTwoByte = chars;
     210          68 : }
     211             : 
     212             : MOZ_ALWAYS_INLINE void
     213       17503 : JSFlatString::init(const JS::Latin1Char* chars, size_t length)
     214             : {
     215       17503 :     d.u1.length = length;
     216       17503 :     d.u1.flags = FLAT_BIT | LATIN1_CHARS_BIT;
     217       17503 :     d.s.u2.nonInlineCharsLatin1 = chars;
     218       17503 : }
     219             : 
     220             : template <js::AllowGC allowGC, typename CharT>
     221             : MOZ_ALWAYS_INLINE JSFlatString*
     222       17569 : JSFlatString::new_(JSContext* cx, const CharT* chars, size_t length)
     223             : {
     224       17569 :     MOZ_ASSERT(chars[length] == CharT(0));
     225             : 
     226       17569 :     if (!validateLength(cx, length))
     227           0 :         return nullptr;
     228             : 
     229             :     JSFlatString* str;
     230       17569 :     if (cx->compartment()->isAtomsCompartment())
     231       13247 :         str = js::Allocate<js::NormalAtom, allowGC>(cx);
     232             :     else
     233        4322 :         str = static_cast<JSFlatString*>(js::Allocate<JSString, allowGC>(cx));
     234       17569 :     if (!str)
     235           0 :         return nullptr;
     236             : 
     237       17569 :     str->init(chars, length);
     238       17569 :     return str;
     239             : }
     240             : 
     241             : inline js::PropertyName*
     242             : JSFlatString::toPropertyName(JSContext* cx)
     243             : {
     244             : #ifdef DEBUG
     245             :     uint32_t dummy;
     246             :     MOZ_ASSERT(!isIndex(&dummy));
     247             : #endif
     248             :     if (isAtom())
     249             :         return asAtom().asPropertyName();
     250             :     JSAtom* atom = js::AtomizeString(cx, this);
     251             :     if (!atom)
     252             :         return nullptr;
     253             :     return atom->asPropertyName();
     254             : }
     255             : 
     256             : template <js::AllowGC allowGC>
     257             : MOZ_ALWAYS_INLINE JSThinInlineString*
     258       51442 : JSThinInlineString::new_(JSContext* cx)
     259             : {
     260       51442 :     if (cx->compartment()->isAtomsCompartment())
     261       46510 :         return (JSThinInlineString*)(js::Allocate<js::NormalAtom, allowGC>(cx));
     262             : 
     263        4932 :     return static_cast<JSThinInlineString*>(js::Allocate<JSString, allowGC>(cx));
     264             : }
     265             : 
     266             : template <js::AllowGC allowGC>
     267             : MOZ_ALWAYS_INLINE JSFatInlineString*
     268       17919 : JSFatInlineString::new_(JSContext* cx)
     269             : {
     270       17919 :     if (cx->compartment()->isAtomsCompartment())
     271       16094 :         return (JSFatInlineString*)(js::Allocate<js::FatInlineAtom, allowGC>(cx));
     272             : 
     273        1825 :     return js::Allocate<JSFatInlineString, allowGC>(cx);
     274             : }
     275             : 
     276             : template<>
     277             : MOZ_ALWAYS_INLINE JS::Latin1Char*
     278       51411 : JSThinInlineString::init<JS::Latin1Char>(size_t length)
     279             : {
     280       51411 :     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
     281       51411 :     d.u1.length = length;
     282       51411 :     d.u1.flags = INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT;
     283       51411 :     return d.inlineStorageLatin1;
     284             : }
     285             : 
     286             : template<>
     287             : MOZ_ALWAYS_INLINE char16_t*
     288          31 : JSThinInlineString::init<char16_t>(size_t length)
     289             : {
     290          31 :     MOZ_ASSERT(lengthFits<char16_t>(length));
     291          31 :     d.u1.length = length;
     292          31 :     d.u1.flags = INIT_THIN_INLINE_FLAGS;
     293          31 :     return d.inlineStorageTwoByte;
     294             : }
     295             : 
     296             : template<>
     297             : MOZ_ALWAYS_INLINE JS::Latin1Char*
     298       17902 : JSFatInlineString::init<JS::Latin1Char>(size_t length)
     299             : {
     300       17902 :     MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
     301       17902 :     d.u1.length = length;
     302       17902 :     d.u1.flags = INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT;
     303       17902 :     return d.inlineStorageLatin1;
     304             : }
     305             : 
     306             : template<>
     307             : MOZ_ALWAYS_INLINE char16_t*
     308          17 : JSFatInlineString::init<char16_t>(size_t length)
     309             : {
     310          17 :     MOZ_ASSERT(lengthFits<char16_t>(length));
     311          17 :     d.u1.length = length;
     312          17 :     d.u1.flags = INIT_FAT_INLINE_FLAGS;
     313          17 :     return d.inlineStorageTwoByte;
     314             : }
     315             : 
     316             : MOZ_ALWAYS_INLINE void
     317         355 : JSExternalString::init(const char16_t* chars, size_t length, const JSStringFinalizer* fin)
     318             : {
     319         355 :     MOZ_ASSERT(fin);
     320         355 :     MOZ_ASSERT(fin->finalize);
     321         355 :     d.u1.length = length;
     322         355 :     d.u1.flags = EXTERNAL_FLAGS;
     323         355 :     d.s.u2.nonInlineCharsTwoByte = chars;
     324         355 :     d.s.u3.externalFinalizer = fin;
     325         355 : }
     326             : 
     327             : MOZ_ALWAYS_INLINE JSExternalString*
     328         355 : JSExternalString::new_(JSContext* cx, const char16_t* chars, size_t length,
     329             :                        const JSStringFinalizer* fin)
     330             : {
     331         355 :     if (!validateLength(cx, length))
     332           0 :         return nullptr;
     333         355 :     JSExternalString* str = js::Allocate<JSExternalString>(cx);
     334         355 :     if (!str)
     335           0 :         return nullptr;
     336         355 :     str->init(chars, length, fin);
     337         355 :     cx->updateMallocCounter((length + 1) * sizeof(char16_t));
     338         355 :     return str;
     339             : }
     340             : 
     341             : inline JSLinearString*
     342          36 : js::StaticStrings::getUnitStringForElement(JSContext* cx, JSString* str, size_t index)
     343             : {
     344          36 :     MOZ_ASSERT(index < str->length());
     345             : 
     346             :     char16_t c;
     347          36 :     if (!str->getChar(cx, index, &c))
     348           0 :         return nullptr;
     349          36 :     if (c < UNIT_STATIC_LIMIT)
     350          34 :         return getUnit(c);
     351           2 :     return NewDependentString(cx, str, index, 1);
     352             : }
     353             : 
     354             : MOZ_ALWAYS_INLINE void
     355           0 : JSString::finalize(js::FreeOp* fop)
     356             : {
     357             :     /* FatInline strings are in a different arena. */
     358           0 :     MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING);
     359           0 :     MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM);
     360             : 
     361           0 :     if (isFlat())
     362           0 :         asFlat().finalize(fop);
     363             :     else
     364           0 :         MOZ_ASSERT(isDependent() || isRope());
     365           0 : }
     366             : 
     367             : inline void
     368           0 : JSFlatString::finalize(js::FreeOp* fop)
     369             : {
     370           0 :     MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING);
     371           0 :     MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM);
     372             : 
     373           0 :     if (!isInline())
     374           0 :         fop->free_(nonInlineCharsRaw());
     375           0 : }
     376             : 
     377             : inline void
     378           0 : JSFatInlineString::finalize(js::FreeOp* fop)
     379             : {
     380           0 :     MOZ_ASSERT(getAllocKind() == js::gc::AllocKind::FAT_INLINE_STRING);
     381             : 
     382           0 :     if (!isInline())
     383           0 :         fop->free_(nonInlineCharsRaw());
     384           0 : }
     385             : 
     386             : inline void
     387           0 : JSAtom::finalize(js::FreeOp* fop)
     388             : {
     389           0 :     MOZ_ASSERT(JSString::isAtom());
     390           0 :     MOZ_ASSERT(JSString::isFlat());
     391           0 :     MOZ_ASSERT(getAllocKind() == js::gc::AllocKind::ATOM ||
     392             :                getAllocKind() == js::gc::AllocKind::FAT_INLINE_ATOM);
     393             : 
     394           0 :     if (!isInline())
     395           0 :         fop->free_(nonInlineCharsRaw());
     396           0 : }
     397             : 
     398             : inline void
     399          15 : JSExternalString::finalize(js::FreeOp* fop)
     400             : {
     401          15 :     if (!JSString::isExternal()) {
     402             :         // This started out as an external string, but was turned into a
     403             :         // non-external string by JSExternalString::ensureFlat.
     404           0 :         MOZ_ASSERT(isFlat());
     405           0 :         fop->free_(nonInlineCharsRaw());
     406           0 :         return;
     407             :     }
     408             : 
     409          15 :     const JSStringFinalizer* fin = externalFinalizer();
     410          15 :     fin->finalize(fin, const_cast<char16_t*>(rawTwoByteChars()));
     411             : }
     412             : 
     413             : #endif /* vm_String_inl_h */

Generated by: LCOV version 1.13