js/src/vm/String-inl.h

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

mercurial