|
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 /* |
|
8 * JS atom table. |
|
9 */ |
|
10 |
|
11 #include "jsatominlines.h" |
|
12 |
|
13 #include "mozilla/ArrayUtils.h" |
|
14 #include "mozilla/RangedPtr.h" |
|
15 |
|
16 #include <string.h> |
|
17 |
|
18 #include "jscntxt.h" |
|
19 #include "jsstr.h" |
|
20 #include "jstypes.h" |
|
21 |
|
22 #include "gc/Marking.h" |
|
23 #include "vm/Xdr.h" |
|
24 |
|
25 #include "jscntxtinlines.h" |
|
26 #include "jscompartmentinlines.h" |
|
27 #include "jsobjinlines.h" |
|
28 |
|
29 #include "vm/String-inl.h" |
|
30 |
|
31 using namespace js; |
|
32 using namespace js::gc; |
|
33 |
|
34 using mozilla::ArrayEnd; |
|
35 using mozilla::ArrayLength; |
|
36 using mozilla::RangedPtr; |
|
37 |
|
38 const char * |
|
39 js::AtomToPrintableString(ExclusiveContext *cx, JSAtom *atom, JSAutoByteString *bytes) |
|
40 { |
|
41 JSString *str = js_QuoteString(cx, atom, 0); |
|
42 if (!str) |
|
43 return nullptr; |
|
44 return bytes->encodeLatin1(cx, str); |
|
45 } |
|
46 |
|
47 const char * const js::TypeStrings[] = { |
|
48 js_undefined_str, |
|
49 js_object_str, |
|
50 js_function_str, |
|
51 js_string_str, |
|
52 js_number_str, |
|
53 js_boolean_str, |
|
54 js_null_str, |
|
55 }; |
|
56 |
|
57 #define DEFINE_PROTO_STRING(name,code,init,clasp) const char js_##name##_str[] = #name; |
|
58 JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING) |
|
59 #undef DEFINE_PROTO_STRING |
|
60 |
|
61 #define CONST_CHAR_STR(idpart, id, text) const char js_##idpart##_str[] = text; |
|
62 FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR) |
|
63 #undef CONST_CHAR_STR |
|
64 |
|
65 /* Constant strings that are not atomized. */ |
|
66 const char js_break_str[] = "break"; |
|
67 const char js_case_str[] = "case"; |
|
68 const char js_catch_str[] = "catch"; |
|
69 const char js_class_str[] = "class"; |
|
70 const char js_close_str[] = "close"; |
|
71 const char js_const_str[] = "const"; |
|
72 const char js_continue_str[] = "continue"; |
|
73 const char js_debugger_str[] = "debugger"; |
|
74 const char js_default_str[] = "default"; |
|
75 const char js_do_str[] = "do"; |
|
76 const char js_else_str[] = "else"; |
|
77 const char js_enum_str[] = "enum"; |
|
78 const char js_export_str[] = "export"; |
|
79 const char js_extends_str[] = "extends"; |
|
80 const char js_finally_str[] = "finally"; |
|
81 const char js_for_str[] = "for"; |
|
82 const char js_getter_str[] = "getter"; |
|
83 const char js_if_str[] = "if"; |
|
84 const char js_implements_str[] = "implements"; |
|
85 const char js_import_str[] = "import"; |
|
86 const char js_in_str[] = "in"; |
|
87 const char js_instanceof_str[] = "instanceof"; |
|
88 const char js_interface_str[] = "interface"; |
|
89 const char js_new_str[] = "new"; |
|
90 const char js_package_str[] = "package"; |
|
91 const char js_private_str[] = "private"; |
|
92 const char js_protected_str[] = "protected"; |
|
93 const char js_public_str[] = "public"; |
|
94 const char js_send_str[] = "send"; |
|
95 const char js_setter_str[] = "setter"; |
|
96 const char js_static_str[] = "static"; |
|
97 const char js_super_str[] = "super"; |
|
98 const char js_switch_str[] = "switch"; |
|
99 const char js_this_str[] = "this"; |
|
100 const char js_try_str[] = "try"; |
|
101 const char js_typeof_str[] = "typeof"; |
|
102 const char js_void_str[] = "void"; |
|
103 const char js_while_str[] = "while"; |
|
104 const char js_with_str[] = "with"; |
|
105 |
|
106 // Use a low initial capacity for atom hash tables to avoid penalizing runtimes |
|
107 // which create a small number of atoms. |
|
108 static const uint32_t JS_STRING_HASH_COUNT = 64; |
|
109 |
|
110 struct CommonNameInfo |
|
111 { |
|
112 const char *str; |
|
113 size_t length; |
|
114 }; |
|
115 |
|
116 bool |
|
117 JSRuntime::initializeAtoms(JSContext *cx) |
|
118 { |
|
119 atoms_ = cx->new_<AtomSet>(); |
|
120 if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT)) |
|
121 return false; |
|
122 |
|
123 if (parentRuntime) { |
|
124 staticStrings = parentRuntime->staticStrings; |
|
125 commonNames = parentRuntime->commonNames; |
|
126 emptyString = parentRuntime->emptyString; |
|
127 permanentAtoms = parentRuntime->permanentAtoms; |
|
128 return true; |
|
129 } |
|
130 |
|
131 permanentAtoms = cx->new_<AtomSet>(); |
|
132 if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT)) |
|
133 return false; |
|
134 |
|
135 staticStrings = cx->new_<StaticStrings>(); |
|
136 if (!staticStrings || !staticStrings->init(cx)) |
|
137 return false; |
|
138 |
|
139 static const CommonNameInfo cachedNames[] = { |
|
140 #define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 }, |
|
141 FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO) |
|
142 #undef COMMON_NAME_INFO |
|
143 #define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 }, |
|
144 JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO) |
|
145 #undef COMMON_NAME_INFO |
|
146 }; |
|
147 |
|
148 commonNames = cx->new_<JSAtomState>(); |
|
149 if (!commonNames) |
|
150 return false; |
|
151 |
|
152 FixedHeapPtr<PropertyName> *names = reinterpret_cast<FixedHeapPtr<PropertyName> *>(commonNames); |
|
153 for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) { |
|
154 JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom); |
|
155 if (!atom) |
|
156 return false; |
|
157 names->init(atom->asPropertyName()); |
|
158 } |
|
159 JS_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1)); |
|
160 |
|
161 emptyString = commonNames->empty; |
|
162 return true; |
|
163 } |
|
164 |
|
165 void |
|
166 JSRuntime::finishAtoms() |
|
167 { |
|
168 if (atoms_) |
|
169 js_delete(atoms_); |
|
170 |
|
171 if (!parentRuntime) { |
|
172 if (staticStrings) |
|
173 js_delete(staticStrings); |
|
174 |
|
175 if (commonNames) |
|
176 js_delete(commonNames); |
|
177 |
|
178 if (permanentAtoms) |
|
179 js_delete(permanentAtoms); |
|
180 } |
|
181 |
|
182 atoms_ = nullptr; |
|
183 staticStrings = nullptr; |
|
184 commonNames = nullptr; |
|
185 permanentAtoms = nullptr; |
|
186 emptyString = nullptr; |
|
187 } |
|
188 |
|
189 void |
|
190 js::MarkAtoms(JSTracer *trc) |
|
191 { |
|
192 JSRuntime *rt = trc->runtime(); |
|
193 for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) { |
|
194 const AtomStateEntry &entry = e.front(); |
|
195 if (!entry.isTagged()) |
|
196 continue; |
|
197 |
|
198 JSAtom *atom = entry.asPtr(); |
|
199 bool tagged = entry.isTagged(); |
|
200 MarkStringRoot(trc, &atom, "interned_atom"); |
|
201 if (entry.asPtr() != atom) |
|
202 e.rekeyFront(AtomHasher::Lookup(atom), AtomStateEntry(atom, tagged)); |
|
203 } |
|
204 } |
|
205 |
|
206 void |
|
207 js::MarkPermanentAtoms(JSTracer *trc) |
|
208 { |
|
209 JSRuntime *rt = trc->runtime(); |
|
210 |
|
211 // Permanent atoms only need to be marked in the runtime which owns them. |
|
212 if (rt->parentRuntime) |
|
213 return; |
|
214 |
|
215 // Static strings are not included in the permanent atoms table. |
|
216 if (rt->staticStrings) |
|
217 rt->staticStrings->trace(trc); |
|
218 |
|
219 if (rt->permanentAtoms) { |
|
220 for (AtomSet::Enum e(*rt->permanentAtoms); !e.empty(); e.popFront()) { |
|
221 const AtomStateEntry &entry = e.front(); |
|
222 |
|
223 JSAtom *atom = entry.asPtr(); |
|
224 MarkPermanentAtom(trc, atom, "permanent_table"); |
|
225 } |
|
226 } |
|
227 } |
|
228 |
|
229 void |
|
230 JSRuntime::sweepAtoms() |
|
231 { |
|
232 if (!atoms_) |
|
233 return; |
|
234 |
|
235 for (AtomSet::Enum e(*atoms_); !e.empty(); e.popFront()) { |
|
236 AtomStateEntry entry = e.front(); |
|
237 JSAtom *atom = entry.asPtr(); |
|
238 bool isDying = IsStringAboutToBeFinalized(&atom); |
|
239 |
|
240 /* Pinned or interned key cannot be finalized. */ |
|
241 JS_ASSERT_IF(hasContexts() && entry.isTagged(), !isDying); |
|
242 |
|
243 if (isDying) |
|
244 e.removeFront(); |
|
245 } |
|
246 } |
|
247 |
|
248 bool |
|
249 JSRuntime::transformToPermanentAtoms() |
|
250 { |
|
251 JS_ASSERT(!parentRuntime); |
|
252 |
|
253 // All static strings were created as permanent atoms, now move the contents |
|
254 // of the atoms table into permanentAtoms and mark each as permanent. |
|
255 |
|
256 JS_ASSERT(permanentAtoms && permanentAtoms->empty()); |
|
257 |
|
258 AtomSet *temp = atoms_; |
|
259 atoms_ = permanentAtoms; |
|
260 permanentAtoms = temp; |
|
261 |
|
262 for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) { |
|
263 AtomStateEntry entry = e.front(); |
|
264 JSAtom *atom = entry.asPtr(); |
|
265 atom->morphIntoPermanentAtom(); |
|
266 } |
|
267 |
|
268 return true; |
|
269 } |
|
270 |
|
271 bool |
|
272 AtomIsInterned(JSContext *cx, JSAtom *atom) |
|
273 { |
|
274 /* We treat static strings as interned because they're never collected. */ |
|
275 if (StaticStrings::isStatic(atom)) |
|
276 return true; |
|
277 |
|
278 AtomHasher::Lookup lookup(atom); |
|
279 |
|
280 /* Likewise, permanent strings are considered to be interned. */ |
|
281 AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); |
|
282 if (p) |
|
283 return true; |
|
284 |
|
285 AutoLockForExclusiveAccess lock(cx); |
|
286 |
|
287 p = cx->runtime()->atoms().lookup(lookup); |
|
288 if (!p) |
|
289 return false; |
|
290 |
|
291 return p->isTagged(); |
|
292 } |
|
293 |
|
294 /* |
|
295 * When the jschars reside in a freshly allocated buffer the memory can be used |
|
296 * as a new JSAtom's storage without copying. The contract is that the caller no |
|
297 * longer owns the memory and this method is responsible for freeing the memory. |
|
298 */ |
|
299 MOZ_ALWAYS_INLINE |
|
300 static JSAtom * |
|
301 AtomizeAndtake(ExclusiveContext *cx, jschar *tbchars, size_t length, InternBehavior ib) |
|
302 { |
|
303 JS_ASSERT(tbchars[length] == 0); |
|
304 |
|
305 if (JSAtom *s = cx->staticStrings().lookup(tbchars, length)) { |
|
306 js_free(tbchars); |
|
307 return s; |
|
308 } |
|
309 |
|
310 AtomHasher::Lookup lookup(tbchars, length); |
|
311 |
|
312 AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); |
|
313 if (pp) { |
|
314 js_free(tbchars); |
|
315 return pp->asPtr(); |
|
316 } |
|
317 |
|
318 AutoLockForExclusiveAccess lock(cx); |
|
319 |
|
320 /* |
|
321 * If a GC occurs at js_NewStringCopy then |p| will still have the correct |
|
322 * hash, allowing us to avoid rehashing it. Even though the hash is |
|
323 * unchanged, we need to re-lookup the table position because a last-ditch |
|
324 * GC will potentially free some table entries. |
|
325 */ |
|
326 AtomSet& atoms = cx->atoms(); |
|
327 AtomSet::AddPtr p = atoms.lookupForAdd(lookup); |
|
328 if (p) { |
|
329 JSAtom *atom = p->asPtr(); |
|
330 p->setTagged(bool(ib)); |
|
331 js_free(tbchars); |
|
332 return atom; |
|
333 } |
|
334 |
|
335 AutoCompartment ac(cx, cx->atomsCompartment()); |
|
336 |
|
337 JSFlatString *flat = js_NewString<NoGC>(cx, tbchars, length); |
|
338 if (!flat) { |
|
339 js_free(tbchars); |
|
340 js_ReportOutOfMemory(cx); |
|
341 return nullptr; |
|
342 } |
|
343 |
|
344 JSAtom *atom = flat->morphAtomizedStringIntoAtom(); |
|
345 |
|
346 if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) { |
|
347 js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */ |
|
348 return nullptr; |
|
349 } |
|
350 |
|
351 return atom; |
|
352 } |
|
353 |
|
354 /* |tbchars| must not point into an inline or short string. */ |
|
355 MOZ_ALWAYS_INLINE |
|
356 static JSAtom * |
|
357 AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, InternBehavior ib) |
|
358 { |
|
359 if (JSAtom *s = cx->staticStrings().lookup(tbchars, length)) |
|
360 return s; |
|
361 |
|
362 AtomHasher::Lookup lookup(tbchars, length); |
|
363 |
|
364 AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); |
|
365 if (pp) |
|
366 return pp->asPtr(); |
|
367 |
|
368 /* |
|
369 * If a GC occurs at js_NewStringCopy then |p| will still have the correct |
|
370 * hash, allowing us to avoid rehashing it. Even though the hash is |
|
371 * unchanged, we need to re-lookup the table position because a last-ditch |
|
372 * GC will potentially free some table entries. |
|
373 */ |
|
374 |
|
375 AutoLockForExclusiveAccess lock(cx); |
|
376 |
|
377 AtomSet& atoms = cx->atoms(); |
|
378 AtomSet::AddPtr p = atoms.lookupForAdd(lookup); |
|
379 if (p) { |
|
380 JSAtom *atom = p->asPtr(); |
|
381 p->setTagged(bool(ib)); |
|
382 return atom; |
|
383 } |
|
384 |
|
385 AutoCompartment ac(cx, cx->atomsCompartment()); |
|
386 |
|
387 JSFlatString *flat = js_NewStringCopyN<NoGC>(cx, tbchars, length); |
|
388 if (!flat) { |
|
389 js_ReportOutOfMemory(cx); |
|
390 return nullptr; |
|
391 } |
|
392 |
|
393 JSAtom *atom = flat->morphAtomizedStringIntoAtom(); |
|
394 |
|
395 if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) { |
|
396 js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */ |
|
397 return nullptr; |
|
398 } |
|
399 |
|
400 return atom; |
|
401 } |
|
402 |
|
403 JSAtom * |
|
404 js::AtomizeString(ExclusiveContext *cx, JSString *str, |
|
405 js::InternBehavior ib /* = js::DoNotInternAtom */) |
|
406 { |
|
407 if (str->isAtom()) { |
|
408 JSAtom &atom = str->asAtom(); |
|
409 /* N.B. static atoms are effectively always interned. */ |
|
410 if (ib != InternAtom || js::StaticStrings::isStatic(&atom)) |
|
411 return &atom; |
|
412 |
|
413 AtomHasher::Lookup lookup(&atom); |
|
414 |
|
415 /* Likewise, permanent atoms are always interned. */ |
|
416 AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); |
|
417 if (p) |
|
418 return &atom; |
|
419 |
|
420 AutoLockForExclusiveAccess lock(cx); |
|
421 |
|
422 p = cx->atoms().lookup(lookup); |
|
423 JS_ASSERT(p); /* Non-static atom must exist in atom state set. */ |
|
424 JS_ASSERT(p->asPtr() == &atom); |
|
425 JS_ASSERT(ib == InternAtom); |
|
426 p->setTagged(bool(ib)); |
|
427 return &atom; |
|
428 } |
|
429 |
|
430 const jschar *chars = str->getChars(cx); |
|
431 if (!chars) |
|
432 return nullptr; |
|
433 |
|
434 return AtomizeAndCopyChars(cx, chars, str->length(), ib); |
|
435 } |
|
436 |
|
437 JSAtom * |
|
438 js::Atomize(ExclusiveContext *cx, const char *bytes, size_t length, InternBehavior ib) |
|
439 { |
|
440 CHECK_REQUEST(cx); |
|
441 |
|
442 if (!JSString::validateLength(cx, length)) |
|
443 return nullptr; |
|
444 |
|
445 static const unsigned ATOMIZE_BUF_MAX = 32; |
|
446 if (length < ATOMIZE_BUF_MAX) { |
|
447 /* |
|
448 * Avoiding the malloc in InflateString on shorter strings saves us |
|
449 * over 20,000 malloc calls on mozilla browser startup. This compares to |
|
450 * only 131 calls where the string is longer than a 31 char (net) buffer. |
|
451 * The vast majority of atomized strings are already in the hashtable. So |
|
452 * js::AtomizeString rarely has to copy the temp string we make. |
|
453 */ |
|
454 jschar inflated[ATOMIZE_BUF_MAX]; |
|
455 InflateStringToBuffer(bytes, length, inflated); |
|
456 return AtomizeAndCopyChars(cx, inflated, length, ib); |
|
457 } |
|
458 |
|
459 jschar *tbcharsZ = InflateString(cx, bytes, &length); |
|
460 if (!tbcharsZ) |
|
461 return nullptr; |
|
462 return AtomizeAndtake(cx, tbcharsZ, length, ib); |
|
463 } |
|
464 |
|
465 JSAtom * |
|
466 js::AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length, InternBehavior ib) |
|
467 { |
|
468 CHECK_REQUEST(cx); |
|
469 |
|
470 if (!JSString::validateLength(cx, length)) |
|
471 return nullptr; |
|
472 |
|
473 return AtomizeAndCopyChars(cx, chars, length, ib); |
|
474 } |
|
475 |
|
476 bool |
|
477 js::IndexToIdSlow(ExclusiveContext *cx, uint32_t index, MutableHandleId idp) |
|
478 { |
|
479 JS_ASSERT(index > JSID_INT_MAX); |
|
480 |
|
481 jschar buf[UINT32_CHAR_BUFFER_LENGTH]; |
|
482 RangedPtr<jschar> end(ArrayEnd(buf), buf, ArrayEnd(buf)); |
|
483 RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end); |
|
484 |
|
485 JSAtom *atom = AtomizeChars(cx, start.get(), end - start); |
|
486 if (!atom) |
|
487 return false; |
|
488 |
|
489 idp.set(JSID_FROM_BITS((size_t)atom)); |
|
490 return true; |
|
491 } |
|
492 |
|
493 template <AllowGC allowGC> |
|
494 static JSAtom * |
|
495 ToAtomSlow(ExclusiveContext *cx, typename MaybeRooted<Value, allowGC>::HandleType arg) |
|
496 { |
|
497 JS_ASSERT(!arg.isString()); |
|
498 |
|
499 Value v = arg; |
|
500 if (!v.isPrimitive()) { |
|
501 if (!cx->shouldBeJSContext() || !allowGC) |
|
502 return nullptr; |
|
503 RootedValue v2(cx, v); |
|
504 if (!ToPrimitive(cx->asJSContext(), JSTYPE_STRING, &v2)) |
|
505 return nullptr; |
|
506 v = v2; |
|
507 } |
|
508 |
|
509 if (v.isString()) |
|
510 return AtomizeString(cx, v.toString()); |
|
511 if (v.isInt32()) |
|
512 return Int32ToAtom(cx, v.toInt32()); |
|
513 if (v.isDouble()) |
|
514 return NumberToAtom(cx, v.toDouble()); |
|
515 if (v.isBoolean()) |
|
516 return v.toBoolean() ? cx->names().true_ : cx->names().false_; |
|
517 if (v.isNull()) |
|
518 return cx->names().null; |
|
519 return cx->names().undefined; |
|
520 } |
|
521 |
|
522 template <AllowGC allowGC> |
|
523 JSAtom * |
|
524 js::ToAtom(ExclusiveContext *cx, typename MaybeRooted<Value, allowGC>::HandleType v) |
|
525 { |
|
526 if (!v.isString()) |
|
527 return ToAtomSlow<allowGC>(cx, v); |
|
528 |
|
529 JSString *str = v.toString(); |
|
530 if (str->isAtom()) |
|
531 return &str->asAtom(); |
|
532 |
|
533 return AtomizeString(cx, str); |
|
534 } |
|
535 |
|
536 template JSAtom * |
|
537 js::ToAtom<CanGC>(ExclusiveContext *cx, HandleValue v); |
|
538 |
|
539 template JSAtom * |
|
540 js::ToAtom<NoGC>(ExclusiveContext *cx, Value v); |
|
541 |
|
542 template<XDRMode mode> |
|
543 bool |
|
544 js::XDRAtom(XDRState<mode> *xdr, MutableHandleAtom atomp) |
|
545 { |
|
546 if (mode == XDR_ENCODE) { |
|
547 uint32_t nchars = atomp->length(); |
|
548 if (!xdr->codeUint32(&nchars)) |
|
549 return false; |
|
550 |
|
551 jschar *chars = const_cast<jschar *>(atomp->getChars(xdr->cx())); |
|
552 if (!chars) |
|
553 return false; |
|
554 |
|
555 return xdr->codeChars(chars, nchars); |
|
556 } |
|
557 |
|
558 /* Avoid JSString allocation for already existing atoms. See bug 321985. */ |
|
559 uint32_t nchars; |
|
560 if (!xdr->codeUint32(&nchars)) |
|
561 return false; |
|
562 |
|
563 JSContext *cx = xdr->cx(); |
|
564 JSAtom *atom; |
|
565 #if IS_LITTLE_ENDIAN |
|
566 /* Directly access the little endian chars in the XDR buffer. */ |
|
567 const jschar *chars = reinterpret_cast<const jschar *>(xdr->buf.read(nchars * sizeof(jschar))); |
|
568 atom = AtomizeChars(cx, chars, nchars); |
|
569 #else |
|
570 /* |
|
571 * We must copy chars to a temporary buffer to convert between little and |
|
572 * big endian data. |
|
573 */ |
|
574 jschar *chars; |
|
575 jschar stackChars[256]; |
|
576 if (nchars <= ArrayLength(stackChars)) { |
|
577 chars = stackChars; |
|
578 } else { |
|
579 /* |
|
580 * This is very uncommon. Don't use the tempLifoAlloc arena for this as |
|
581 * most allocations here will be bigger than tempLifoAlloc's default |
|
582 * chunk size. |
|
583 */ |
|
584 chars = cx->runtime()->pod_malloc<jschar>(nchars); |
|
585 if (!chars) |
|
586 return false; |
|
587 } |
|
588 |
|
589 JS_ALWAYS_TRUE(xdr->codeChars(chars, nchars)); |
|
590 atom = AtomizeChars(cx, chars, nchars); |
|
591 if (chars != stackChars) |
|
592 js_free(chars); |
|
593 #endif /* !IS_LITTLE_ENDIAN */ |
|
594 |
|
595 if (!atom) |
|
596 return false; |
|
597 atomp.set(atom); |
|
598 return true; |
|
599 } |
|
600 |
|
601 template bool |
|
602 js::XDRAtom(XDRState<XDR_ENCODE> *xdr, MutableHandleAtom atomp); |
|
603 |
|
604 template bool |
|
605 js::XDRAtom(XDRState<XDR_DECODE> *xdr, MutableHandleAtom atomp); |
|
606 |