js/src/vm/String-inl.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef vm_String_inl_h
michael@0 8 #define vm_String_inl_h
michael@0 9
michael@0 10 #include "vm/String.h"
michael@0 11
michael@0 12 #include "mozilla/PodOperations.h"
michael@0 13
michael@0 14 #include "jscntxt.h"
michael@0 15
michael@0 16 #include "gc/Marking.h"
michael@0 17
michael@0 18 #include "jsgcinlines.h"
michael@0 19
michael@0 20 namespace js {
michael@0 21
michael@0 22 template <AllowGC allowGC>
michael@0 23 static MOZ_ALWAYS_INLINE JSInlineString *
michael@0 24 NewFatInlineString(ThreadSafeContext *cx, JS::Latin1Chars chars)
michael@0 25 {
michael@0 26 size_t len = chars.length();
michael@0 27 JS_ASSERT(JSFatInlineString::lengthFits(len));
michael@0 28 JSInlineString *str = JSInlineString::lengthFits(len)
michael@0 29 ? JSInlineString::new_<allowGC>(cx)
michael@0 30 : JSFatInlineString::new_<allowGC>(cx);
michael@0 31 if (!str)
michael@0 32 return nullptr;
michael@0 33
michael@0 34 jschar *p = str->init(len);
michael@0 35 for (size_t i = 0; i < len; ++i)
michael@0 36 p[i] = static_cast<jschar>(chars[i]);
michael@0 37 p[len] = '\0';
michael@0 38 return str;
michael@0 39 }
michael@0 40
michael@0 41 template <AllowGC allowGC>
michael@0 42 static MOZ_ALWAYS_INLINE JSInlineString *
michael@0 43 NewFatInlineString(ExclusiveContext *cx, JS::TwoByteChars chars)
michael@0 44 {
michael@0 45 size_t len = chars.length();
michael@0 46
michael@0 47 /*
michael@0 48 * Don't bother trying to find a static atom; measurement shows that not
michael@0 49 * many get here (for one, Atomize is catching them).
michael@0 50 */
michael@0 51 JS_ASSERT(JSFatInlineString::lengthFits(len));
michael@0 52 JSInlineString *str = JSInlineString::lengthFits(len)
michael@0 53 ? JSInlineString::new_<allowGC>(cx)
michael@0 54 : JSFatInlineString::new_<allowGC>(cx);
michael@0 55 if (!str)
michael@0 56 return nullptr;
michael@0 57
michael@0 58 jschar *storage = str->init(len);
michael@0 59 mozilla::PodCopy(storage, chars.start().get(), len);
michael@0 60 storage[len] = 0;
michael@0 61 return str;
michael@0 62 }
michael@0 63
michael@0 64 static inline void
michael@0 65 StringWriteBarrierPost(js::ThreadSafeContext *maybecx, JSString **strp)
michael@0 66 {
michael@0 67 }
michael@0 68
michael@0 69 static inline void
michael@0 70 StringWriteBarrierPostRemove(js::ThreadSafeContext *maybecx, JSString **strp)
michael@0 71 {
michael@0 72 }
michael@0 73
michael@0 74 } /* namespace js */
michael@0 75
michael@0 76 MOZ_ALWAYS_INLINE bool
michael@0 77 JSString::validateLength(js::ThreadSafeContext *maybecx, size_t length)
michael@0 78 {
michael@0 79 if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
michael@0 80 js_ReportAllocationOverflow(maybecx);
michael@0 81 return false;
michael@0 82 }
michael@0 83
michael@0 84 return true;
michael@0 85 }
michael@0 86
michael@0 87 MOZ_ALWAYS_INLINE void
michael@0 88 JSRope::init(js::ThreadSafeContext *cx, JSString *left, JSString *right, size_t length)
michael@0 89 {
michael@0 90 d.lengthAndFlags = buildLengthAndFlags(length, ROPE_FLAGS);
michael@0 91 d.u1.left = left;
michael@0 92 d.s.u2.right = right;
michael@0 93 js::StringWriteBarrierPost(cx, &d.u1.left);
michael@0 94 js::StringWriteBarrierPost(cx, &d.s.u2.right);
michael@0 95 }
michael@0 96
michael@0 97 template <js::AllowGC allowGC>
michael@0 98 MOZ_ALWAYS_INLINE JSRope *
michael@0 99 JSRope::new_(js::ThreadSafeContext *cx,
michael@0 100 typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
michael@0 101 typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
michael@0 102 size_t length)
michael@0 103 {
michael@0 104 if (!validateLength(cx, length))
michael@0 105 return nullptr;
michael@0 106 JSRope *str = (JSRope *) js_NewGCString<allowGC>(cx);
michael@0 107 if (!str)
michael@0 108 return nullptr;
michael@0 109 str->init(cx, left, right, length);
michael@0 110 return str;
michael@0 111 }
michael@0 112
michael@0 113 inline void
michael@0 114 JSRope::markChildren(JSTracer *trc)
michael@0 115 {
michael@0 116 js::gc::MarkStringUnbarriered(trc, &d.u1.left, "left child");
michael@0 117 js::gc::MarkStringUnbarriered(trc, &d.s.u2.right, "right child");
michael@0 118 }
michael@0 119
michael@0 120 MOZ_ALWAYS_INLINE void
michael@0 121 JSDependentString::init(js::ThreadSafeContext *cx, JSLinearString *base, const jschar *chars,
michael@0 122 size_t length)
michael@0 123 {
michael@0 124 JS_ASSERT(!js::IsPoisonedPtr(base));
michael@0 125 d.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_FLAGS);
michael@0 126 d.u1.chars = chars;
michael@0 127 d.s.u2.base = base;
michael@0 128 js::StringWriteBarrierPost(cx, reinterpret_cast<JSString **>(&d.s.u2.base));
michael@0 129 }
michael@0 130
michael@0 131 MOZ_ALWAYS_INLINE JSLinearString *
michael@0 132 JSDependentString::new_(js::ExclusiveContext *cx,
michael@0 133 JSLinearString *baseArg, const jschar *chars, size_t length)
michael@0 134 {
michael@0 135 /* Try to avoid long chains of dependent strings. */
michael@0 136 while (baseArg->isDependent())
michael@0 137 baseArg = baseArg->asDependent().base();
michael@0 138
michael@0 139 JS_ASSERT(baseArg->isFlat());
michael@0 140
michael@0 141 /*
michael@0 142 * The chars we are pointing into must be owned by something in the chain
michael@0 143 * of dependent or undepended strings kept alive by our base pointer.
michael@0 144 */
michael@0 145 #ifdef DEBUG
michael@0 146 for (JSLinearString *b = baseArg; ; b = b->base()) {
michael@0 147 if (chars >= b->chars() && chars < b->chars() + b->length() &&
michael@0 148 length <= b->length() - (chars - b->chars()))
michael@0 149 {
michael@0 150 break;
michael@0 151 }
michael@0 152 }
michael@0 153 #endif
michael@0 154
michael@0 155 /*
michael@0 156 * Do not create a string dependent on inline chars from another string,
michael@0 157 * both to avoid the awkward moving-GC hazard this introduces and because it
michael@0 158 * is more efficient to immediately undepend here.
michael@0 159 */
michael@0 160 if (JSFatInlineString::lengthFits(length))
michael@0 161 return js::NewFatInlineString<js::CanGC>(cx, JS::TwoByteChars(chars, length));
michael@0 162
michael@0 163 JSDependentString *str = (JSDependentString *)js_NewGCString<js::NoGC>(cx);
michael@0 164 if (str) {
michael@0 165 str->init(cx, baseArg, chars, length);
michael@0 166 return str;
michael@0 167 }
michael@0 168
michael@0 169 JS::Rooted<JSLinearString*> base(cx, baseArg);
michael@0 170
michael@0 171 str = (JSDependentString *)js_NewGCString<js::CanGC>(cx);
michael@0 172 if (!str)
michael@0 173 return nullptr;
michael@0 174 str->init(cx, base, chars, length);
michael@0 175 return str;
michael@0 176 }
michael@0 177
michael@0 178 inline void
michael@0 179 JSString::markBase(JSTracer *trc)
michael@0 180 {
michael@0 181 JS_ASSERT(hasBase());
michael@0 182 js::gc::MarkStringUnbarriered(trc, &d.s.u2.base, "base");
michael@0 183 }
michael@0 184
michael@0 185 MOZ_ALWAYS_INLINE void
michael@0 186 JSFlatString::init(const jschar *chars, size_t length)
michael@0 187 {
michael@0 188 d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
michael@0 189 d.u1.chars = chars;
michael@0 190 }
michael@0 191
michael@0 192 template <js::AllowGC allowGC>
michael@0 193 MOZ_ALWAYS_INLINE JSFlatString *
michael@0 194 JSFlatString::new_(js::ThreadSafeContext *cx, const jschar *chars, size_t length)
michael@0 195 {
michael@0 196 JS_ASSERT(chars[length] == jschar(0));
michael@0 197
michael@0 198 if (!validateLength(cx, length))
michael@0 199 return nullptr;
michael@0 200 JSFlatString *str = (JSFlatString *)js_NewGCString<allowGC>(cx);
michael@0 201 if (!str)
michael@0 202 return nullptr;
michael@0 203 str->init(chars, length);
michael@0 204 return str;
michael@0 205 }
michael@0 206
michael@0 207 inline js::PropertyName *
michael@0 208 JSFlatString::toPropertyName(JSContext *cx)
michael@0 209 {
michael@0 210 #ifdef DEBUG
michael@0 211 uint32_t dummy;
michael@0 212 JS_ASSERT(!isIndex(&dummy));
michael@0 213 #endif
michael@0 214 if (isAtom())
michael@0 215 return asAtom().asPropertyName();
michael@0 216 JSAtom *atom = js::AtomizeString(cx, this);
michael@0 217 if (!atom)
michael@0 218 return nullptr;
michael@0 219 return atom->asPropertyName();
michael@0 220 }
michael@0 221
michael@0 222 template <js::AllowGC allowGC>
michael@0 223 MOZ_ALWAYS_INLINE JSInlineString *
michael@0 224 JSInlineString::new_(js::ThreadSafeContext *cx)
michael@0 225 {
michael@0 226 return (JSInlineString *)js_NewGCString<allowGC>(cx);
michael@0 227 }
michael@0 228
michael@0 229 MOZ_ALWAYS_INLINE jschar *
michael@0 230 JSInlineString::init(size_t length)
michael@0 231 {
michael@0 232 d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
michael@0 233 d.u1.chars = d.inlineStorage;
michael@0 234 JS_ASSERT(lengthFits(length) || (isFatInline() && JSFatInlineString::lengthFits(length)));
michael@0 235 return d.inlineStorage;
michael@0 236 }
michael@0 237
michael@0 238 MOZ_ALWAYS_INLINE void
michael@0 239 JSInlineString::resetLength(size_t length)
michael@0 240 {
michael@0 241 d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
michael@0 242 JS_ASSERT(lengthFits(length) || (isFatInline() && JSFatInlineString::lengthFits(length)));
michael@0 243 }
michael@0 244
michael@0 245 template <js::AllowGC allowGC>
michael@0 246 MOZ_ALWAYS_INLINE JSFatInlineString *
michael@0 247 JSFatInlineString::new_(js::ThreadSafeContext *cx)
michael@0 248 {
michael@0 249 return js_NewGCFatInlineString<allowGC>(cx);
michael@0 250 }
michael@0 251
michael@0 252 MOZ_ALWAYS_INLINE void
michael@0 253 JSExternalString::init(const jschar *chars, size_t length, const JSStringFinalizer *fin)
michael@0 254 {
michael@0 255 JS_ASSERT(fin);
michael@0 256 JS_ASSERT(fin->finalize);
michael@0 257 d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
michael@0 258 d.u1.chars = chars;
michael@0 259 d.s.u2.externalFinalizer = fin;
michael@0 260 }
michael@0 261
michael@0 262 MOZ_ALWAYS_INLINE JSExternalString *
michael@0 263 JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length,
michael@0 264 const JSStringFinalizer *fin)
michael@0 265 {
michael@0 266 JS_ASSERT(chars[length] == 0);
michael@0 267
michael@0 268 if (!validateLength(cx, length))
michael@0 269 return nullptr;
michael@0 270 JSExternalString *str = js_NewGCExternalString(cx);
michael@0 271 if (!str)
michael@0 272 return nullptr;
michael@0 273 str->init(chars, length, fin);
michael@0 274 cx->runtime()->updateMallocCounter(cx->zone(), (length + 1) * sizeof(jschar));
michael@0 275 return str;
michael@0 276 }
michael@0 277
michael@0 278 inline JSLinearString *
michael@0 279 js::StaticStrings::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
michael@0 280 {
michael@0 281 JS_ASSERT(index < str->length());
michael@0 282
michael@0 283 jschar c;
michael@0 284 if (!str->getChar(cx, index, &c))
michael@0 285 return nullptr;
michael@0 286 if (c < UNIT_STATIC_LIMIT)
michael@0 287 return getUnit(c);
michael@0 288 return js_NewDependentString(cx, str, index, 1);
michael@0 289 }
michael@0 290
michael@0 291 inline JSAtom *
michael@0 292 js::StaticStrings::getLength2(jschar c1, jschar c2)
michael@0 293 {
michael@0 294 JS_ASSERT(fitsInSmallChar(c1));
michael@0 295 JS_ASSERT(fitsInSmallChar(c2));
michael@0 296 size_t index = (((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2];
michael@0 297 return length2StaticTable[index];
michael@0 298 }
michael@0 299
michael@0 300 MOZ_ALWAYS_INLINE void
michael@0 301 JSString::finalize(js::FreeOp *fop)
michael@0 302 {
michael@0 303 /* FatInline strings are in a different arena. */
michael@0 304 JS_ASSERT(getAllocKind() != js::gc::FINALIZE_FAT_INLINE_STRING);
michael@0 305
michael@0 306 if (isFlat())
michael@0 307 asFlat().finalize(fop);
michael@0 308 else
michael@0 309 JS_ASSERT(isDependent() || isRope());
michael@0 310 }
michael@0 311
michael@0 312 inline void
michael@0 313 JSFlatString::finalize(js::FreeOp *fop)
michael@0 314 {
michael@0 315 JS_ASSERT(getAllocKind() != js::gc::FINALIZE_FAT_INLINE_STRING);
michael@0 316
michael@0 317 if (chars() != d.inlineStorage)
michael@0 318 fop->free_(const_cast<jschar *>(chars()));
michael@0 319 }
michael@0 320
michael@0 321 inline void
michael@0 322 JSFatInlineString::finalize(js::FreeOp *fop)
michael@0 323 {
michael@0 324 JS_ASSERT(getAllocKind() == js::gc::FINALIZE_FAT_INLINE_STRING);
michael@0 325
michael@0 326 if (chars() != d.inlineStorage)
michael@0 327 fop->free_(const_cast<jschar *>(chars()));
michael@0 328 }
michael@0 329
michael@0 330 inline void
michael@0 331 JSAtom::finalize(js::FreeOp *fop)
michael@0 332 {
michael@0 333 JS_ASSERT(JSString::isAtom());
michael@0 334 JS_ASSERT(JSString::isFlat());
michael@0 335
michael@0 336 if (chars() != d.inlineStorage)
michael@0 337 fop->free_(const_cast<jschar *>(chars()));
michael@0 338 }
michael@0 339
michael@0 340 inline void
michael@0 341 JSExternalString::finalize(js::FreeOp *fop)
michael@0 342 {
michael@0 343 const JSStringFinalizer *fin = externalFinalizer();
michael@0 344 fin->finalize(fin, const_cast<jschar *>(chars()));
michael@0 345 }
michael@0 346
michael@0 347 #endif /* vm_String_inl_h */

mercurial