1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsatom.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,606 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS atom table. 1.12 + */ 1.13 + 1.14 +#include "jsatominlines.h" 1.15 + 1.16 +#include "mozilla/ArrayUtils.h" 1.17 +#include "mozilla/RangedPtr.h" 1.18 + 1.19 +#include <string.h> 1.20 + 1.21 +#include "jscntxt.h" 1.22 +#include "jsstr.h" 1.23 +#include "jstypes.h" 1.24 + 1.25 +#include "gc/Marking.h" 1.26 +#include "vm/Xdr.h" 1.27 + 1.28 +#include "jscntxtinlines.h" 1.29 +#include "jscompartmentinlines.h" 1.30 +#include "jsobjinlines.h" 1.31 + 1.32 +#include "vm/String-inl.h" 1.33 + 1.34 +using namespace js; 1.35 +using namespace js::gc; 1.36 + 1.37 +using mozilla::ArrayEnd; 1.38 +using mozilla::ArrayLength; 1.39 +using mozilla::RangedPtr; 1.40 + 1.41 +const char * 1.42 +js::AtomToPrintableString(ExclusiveContext *cx, JSAtom *atom, JSAutoByteString *bytes) 1.43 +{ 1.44 + JSString *str = js_QuoteString(cx, atom, 0); 1.45 + if (!str) 1.46 + return nullptr; 1.47 + return bytes->encodeLatin1(cx, str); 1.48 +} 1.49 + 1.50 +const char * const js::TypeStrings[] = { 1.51 + js_undefined_str, 1.52 + js_object_str, 1.53 + js_function_str, 1.54 + js_string_str, 1.55 + js_number_str, 1.56 + js_boolean_str, 1.57 + js_null_str, 1.58 +}; 1.59 + 1.60 +#define DEFINE_PROTO_STRING(name,code,init,clasp) const char js_##name##_str[] = #name; 1.61 +JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING) 1.62 +#undef DEFINE_PROTO_STRING 1.63 + 1.64 +#define CONST_CHAR_STR(idpart, id, text) const char js_##idpart##_str[] = text; 1.65 +FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR) 1.66 +#undef CONST_CHAR_STR 1.67 + 1.68 +/* Constant strings that are not atomized. */ 1.69 +const char js_break_str[] = "break"; 1.70 +const char js_case_str[] = "case"; 1.71 +const char js_catch_str[] = "catch"; 1.72 +const char js_class_str[] = "class"; 1.73 +const char js_close_str[] = "close"; 1.74 +const char js_const_str[] = "const"; 1.75 +const char js_continue_str[] = "continue"; 1.76 +const char js_debugger_str[] = "debugger"; 1.77 +const char js_default_str[] = "default"; 1.78 +const char js_do_str[] = "do"; 1.79 +const char js_else_str[] = "else"; 1.80 +const char js_enum_str[] = "enum"; 1.81 +const char js_export_str[] = "export"; 1.82 +const char js_extends_str[] = "extends"; 1.83 +const char js_finally_str[] = "finally"; 1.84 +const char js_for_str[] = "for"; 1.85 +const char js_getter_str[] = "getter"; 1.86 +const char js_if_str[] = "if"; 1.87 +const char js_implements_str[] = "implements"; 1.88 +const char js_import_str[] = "import"; 1.89 +const char js_in_str[] = "in"; 1.90 +const char js_instanceof_str[] = "instanceof"; 1.91 +const char js_interface_str[] = "interface"; 1.92 +const char js_new_str[] = "new"; 1.93 +const char js_package_str[] = "package"; 1.94 +const char js_private_str[] = "private"; 1.95 +const char js_protected_str[] = "protected"; 1.96 +const char js_public_str[] = "public"; 1.97 +const char js_send_str[] = "send"; 1.98 +const char js_setter_str[] = "setter"; 1.99 +const char js_static_str[] = "static"; 1.100 +const char js_super_str[] = "super"; 1.101 +const char js_switch_str[] = "switch"; 1.102 +const char js_this_str[] = "this"; 1.103 +const char js_try_str[] = "try"; 1.104 +const char js_typeof_str[] = "typeof"; 1.105 +const char js_void_str[] = "void"; 1.106 +const char js_while_str[] = "while"; 1.107 +const char js_with_str[] = "with"; 1.108 + 1.109 +// Use a low initial capacity for atom hash tables to avoid penalizing runtimes 1.110 +// which create a small number of atoms. 1.111 +static const uint32_t JS_STRING_HASH_COUNT = 64; 1.112 + 1.113 +struct CommonNameInfo 1.114 +{ 1.115 + const char *str; 1.116 + size_t length; 1.117 +}; 1.118 + 1.119 +bool 1.120 +JSRuntime::initializeAtoms(JSContext *cx) 1.121 +{ 1.122 + atoms_ = cx->new_<AtomSet>(); 1.123 + if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT)) 1.124 + return false; 1.125 + 1.126 + if (parentRuntime) { 1.127 + staticStrings = parentRuntime->staticStrings; 1.128 + commonNames = parentRuntime->commonNames; 1.129 + emptyString = parentRuntime->emptyString; 1.130 + permanentAtoms = parentRuntime->permanentAtoms; 1.131 + return true; 1.132 + } 1.133 + 1.134 + permanentAtoms = cx->new_<AtomSet>(); 1.135 + if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT)) 1.136 + return false; 1.137 + 1.138 + staticStrings = cx->new_<StaticStrings>(); 1.139 + if (!staticStrings || !staticStrings->init(cx)) 1.140 + return false; 1.141 + 1.142 + static const CommonNameInfo cachedNames[] = { 1.143 +#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 }, 1.144 + FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO) 1.145 +#undef COMMON_NAME_INFO 1.146 +#define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 }, 1.147 + JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO) 1.148 +#undef COMMON_NAME_INFO 1.149 + }; 1.150 + 1.151 + commonNames = cx->new_<JSAtomState>(); 1.152 + if (!commonNames) 1.153 + return false; 1.154 + 1.155 + FixedHeapPtr<PropertyName> *names = reinterpret_cast<FixedHeapPtr<PropertyName> *>(commonNames); 1.156 + for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) { 1.157 + JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom); 1.158 + if (!atom) 1.159 + return false; 1.160 + names->init(atom->asPropertyName()); 1.161 + } 1.162 + JS_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1)); 1.163 + 1.164 + emptyString = commonNames->empty; 1.165 + return true; 1.166 +} 1.167 + 1.168 +void 1.169 +JSRuntime::finishAtoms() 1.170 +{ 1.171 + if (atoms_) 1.172 + js_delete(atoms_); 1.173 + 1.174 + if (!parentRuntime) { 1.175 + if (staticStrings) 1.176 + js_delete(staticStrings); 1.177 + 1.178 + if (commonNames) 1.179 + js_delete(commonNames); 1.180 + 1.181 + if (permanentAtoms) 1.182 + js_delete(permanentAtoms); 1.183 + } 1.184 + 1.185 + atoms_ = nullptr; 1.186 + staticStrings = nullptr; 1.187 + commonNames = nullptr; 1.188 + permanentAtoms = nullptr; 1.189 + emptyString = nullptr; 1.190 +} 1.191 + 1.192 +void 1.193 +js::MarkAtoms(JSTracer *trc) 1.194 +{ 1.195 + JSRuntime *rt = trc->runtime(); 1.196 + for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) { 1.197 + const AtomStateEntry &entry = e.front(); 1.198 + if (!entry.isTagged()) 1.199 + continue; 1.200 + 1.201 + JSAtom *atom = entry.asPtr(); 1.202 + bool tagged = entry.isTagged(); 1.203 + MarkStringRoot(trc, &atom, "interned_atom"); 1.204 + if (entry.asPtr() != atom) 1.205 + e.rekeyFront(AtomHasher::Lookup(atom), AtomStateEntry(atom, tagged)); 1.206 + } 1.207 +} 1.208 + 1.209 +void 1.210 +js::MarkPermanentAtoms(JSTracer *trc) 1.211 +{ 1.212 + JSRuntime *rt = trc->runtime(); 1.213 + 1.214 + // Permanent atoms only need to be marked in the runtime which owns them. 1.215 + if (rt->parentRuntime) 1.216 + return; 1.217 + 1.218 + // Static strings are not included in the permanent atoms table. 1.219 + if (rt->staticStrings) 1.220 + rt->staticStrings->trace(trc); 1.221 + 1.222 + if (rt->permanentAtoms) { 1.223 + for (AtomSet::Enum e(*rt->permanentAtoms); !e.empty(); e.popFront()) { 1.224 + const AtomStateEntry &entry = e.front(); 1.225 + 1.226 + JSAtom *atom = entry.asPtr(); 1.227 + MarkPermanentAtom(trc, atom, "permanent_table"); 1.228 + } 1.229 + } 1.230 +} 1.231 + 1.232 +void 1.233 +JSRuntime::sweepAtoms() 1.234 +{ 1.235 + if (!atoms_) 1.236 + return; 1.237 + 1.238 + for (AtomSet::Enum e(*atoms_); !e.empty(); e.popFront()) { 1.239 + AtomStateEntry entry = e.front(); 1.240 + JSAtom *atom = entry.asPtr(); 1.241 + bool isDying = IsStringAboutToBeFinalized(&atom); 1.242 + 1.243 + /* Pinned or interned key cannot be finalized. */ 1.244 + JS_ASSERT_IF(hasContexts() && entry.isTagged(), !isDying); 1.245 + 1.246 + if (isDying) 1.247 + e.removeFront(); 1.248 + } 1.249 +} 1.250 + 1.251 +bool 1.252 +JSRuntime::transformToPermanentAtoms() 1.253 +{ 1.254 + JS_ASSERT(!parentRuntime); 1.255 + 1.256 + // All static strings were created as permanent atoms, now move the contents 1.257 + // of the atoms table into permanentAtoms and mark each as permanent. 1.258 + 1.259 + JS_ASSERT(permanentAtoms && permanentAtoms->empty()); 1.260 + 1.261 + AtomSet *temp = atoms_; 1.262 + atoms_ = permanentAtoms; 1.263 + permanentAtoms = temp; 1.264 + 1.265 + for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) { 1.266 + AtomStateEntry entry = e.front(); 1.267 + JSAtom *atom = entry.asPtr(); 1.268 + atom->morphIntoPermanentAtom(); 1.269 + } 1.270 + 1.271 + return true; 1.272 +} 1.273 + 1.274 +bool 1.275 +AtomIsInterned(JSContext *cx, JSAtom *atom) 1.276 +{ 1.277 + /* We treat static strings as interned because they're never collected. */ 1.278 + if (StaticStrings::isStatic(atom)) 1.279 + return true; 1.280 + 1.281 + AtomHasher::Lookup lookup(atom); 1.282 + 1.283 + /* Likewise, permanent strings are considered to be interned. */ 1.284 + AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); 1.285 + if (p) 1.286 + return true; 1.287 + 1.288 + AutoLockForExclusiveAccess lock(cx); 1.289 + 1.290 + p = cx->runtime()->atoms().lookup(lookup); 1.291 + if (!p) 1.292 + return false; 1.293 + 1.294 + return p->isTagged(); 1.295 +} 1.296 + 1.297 +/* 1.298 + * When the jschars reside in a freshly allocated buffer the memory can be used 1.299 + * as a new JSAtom's storage without copying. The contract is that the caller no 1.300 + * longer owns the memory and this method is responsible for freeing the memory. 1.301 + */ 1.302 +MOZ_ALWAYS_INLINE 1.303 +static JSAtom * 1.304 +AtomizeAndtake(ExclusiveContext *cx, jschar *tbchars, size_t length, InternBehavior ib) 1.305 +{ 1.306 + JS_ASSERT(tbchars[length] == 0); 1.307 + 1.308 + if (JSAtom *s = cx->staticStrings().lookup(tbchars, length)) { 1.309 + js_free(tbchars); 1.310 + return s; 1.311 + } 1.312 + 1.313 + AtomHasher::Lookup lookup(tbchars, length); 1.314 + 1.315 + AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); 1.316 + if (pp) { 1.317 + js_free(tbchars); 1.318 + return pp->asPtr(); 1.319 + } 1.320 + 1.321 + AutoLockForExclusiveAccess lock(cx); 1.322 + 1.323 + /* 1.324 + * If a GC occurs at js_NewStringCopy then |p| will still have the correct 1.325 + * hash, allowing us to avoid rehashing it. Even though the hash is 1.326 + * unchanged, we need to re-lookup the table position because a last-ditch 1.327 + * GC will potentially free some table entries. 1.328 + */ 1.329 + AtomSet& atoms = cx->atoms(); 1.330 + AtomSet::AddPtr p = atoms.lookupForAdd(lookup); 1.331 + if (p) { 1.332 + JSAtom *atom = p->asPtr(); 1.333 + p->setTagged(bool(ib)); 1.334 + js_free(tbchars); 1.335 + return atom; 1.336 + } 1.337 + 1.338 + AutoCompartment ac(cx, cx->atomsCompartment()); 1.339 + 1.340 + JSFlatString *flat = js_NewString<NoGC>(cx, tbchars, length); 1.341 + if (!flat) { 1.342 + js_free(tbchars); 1.343 + js_ReportOutOfMemory(cx); 1.344 + return nullptr; 1.345 + } 1.346 + 1.347 + JSAtom *atom = flat->morphAtomizedStringIntoAtom(); 1.348 + 1.349 + if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) { 1.350 + js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */ 1.351 + return nullptr; 1.352 + } 1.353 + 1.354 + return atom; 1.355 +} 1.356 + 1.357 +/* |tbchars| must not point into an inline or short string. */ 1.358 +MOZ_ALWAYS_INLINE 1.359 +static JSAtom * 1.360 +AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, InternBehavior ib) 1.361 +{ 1.362 + if (JSAtom *s = cx->staticStrings().lookup(tbchars, length)) 1.363 + return s; 1.364 + 1.365 + AtomHasher::Lookup lookup(tbchars, length); 1.366 + 1.367 + AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); 1.368 + if (pp) 1.369 + return pp->asPtr(); 1.370 + 1.371 + /* 1.372 + * If a GC occurs at js_NewStringCopy then |p| will still have the correct 1.373 + * hash, allowing us to avoid rehashing it. Even though the hash is 1.374 + * unchanged, we need to re-lookup the table position because a last-ditch 1.375 + * GC will potentially free some table entries. 1.376 + */ 1.377 + 1.378 + AutoLockForExclusiveAccess lock(cx); 1.379 + 1.380 + AtomSet& atoms = cx->atoms(); 1.381 + AtomSet::AddPtr p = atoms.lookupForAdd(lookup); 1.382 + if (p) { 1.383 + JSAtom *atom = p->asPtr(); 1.384 + p->setTagged(bool(ib)); 1.385 + return atom; 1.386 + } 1.387 + 1.388 + AutoCompartment ac(cx, cx->atomsCompartment()); 1.389 + 1.390 + JSFlatString *flat = js_NewStringCopyN<NoGC>(cx, tbchars, length); 1.391 + if (!flat) { 1.392 + js_ReportOutOfMemory(cx); 1.393 + return nullptr; 1.394 + } 1.395 + 1.396 + JSAtom *atom = flat->morphAtomizedStringIntoAtom(); 1.397 + 1.398 + if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) { 1.399 + js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */ 1.400 + return nullptr; 1.401 + } 1.402 + 1.403 + return atom; 1.404 +} 1.405 + 1.406 +JSAtom * 1.407 +js::AtomizeString(ExclusiveContext *cx, JSString *str, 1.408 + js::InternBehavior ib /* = js::DoNotInternAtom */) 1.409 +{ 1.410 + if (str->isAtom()) { 1.411 + JSAtom &atom = str->asAtom(); 1.412 + /* N.B. static atoms are effectively always interned. */ 1.413 + if (ib != InternAtom || js::StaticStrings::isStatic(&atom)) 1.414 + return &atom; 1.415 + 1.416 + AtomHasher::Lookup lookup(&atom); 1.417 + 1.418 + /* Likewise, permanent atoms are always interned. */ 1.419 + AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup); 1.420 + if (p) 1.421 + return &atom; 1.422 + 1.423 + AutoLockForExclusiveAccess lock(cx); 1.424 + 1.425 + p = cx->atoms().lookup(lookup); 1.426 + JS_ASSERT(p); /* Non-static atom must exist in atom state set. */ 1.427 + JS_ASSERT(p->asPtr() == &atom); 1.428 + JS_ASSERT(ib == InternAtom); 1.429 + p->setTagged(bool(ib)); 1.430 + return &atom; 1.431 + } 1.432 + 1.433 + const jschar *chars = str->getChars(cx); 1.434 + if (!chars) 1.435 + return nullptr; 1.436 + 1.437 + return AtomizeAndCopyChars(cx, chars, str->length(), ib); 1.438 +} 1.439 + 1.440 +JSAtom * 1.441 +js::Atomize(ExclusiveContext *cx, const char *bytes, size_t length, InternBehavior ib) 1.442 +{ 1.443 + CHECK_REQUEST(cx); 1.444 + 1.445 + if (!JSString::validateLength(cx, length)) 1.446 + return nullptr; 1.447 + 1.448 + static const unsigned ATOMIZE_BUF_MAX = 32; 1.449 + if (length < ATOMIZE_BUF_MAX) { 1.450 + /* 1.451 + * Avoiding the malloc in InflateString on shorter strings saves us 1.452 + * over 20,000 malloc calls on mozilla browser startup. This compares to 1.453 + * only 131 calls where the string is longer than a 31 char (net) buffer. 1.454 + * The vast majority of atomized strings are already in the hashtable. So 1.455 + * js::AtomizeString rarely has to copy the temp string we make. 1.456 + */ 1.457 + jschar inflated[ATOMIZE_BUF_MAX]; 1.458 + InflateStringToBuffer(bytes, length, inflated); 1.459 + return AtomizeAndCopyChars(cx, inflated, length, ib); 1.460 + } 1.461 + 1.462 + jschar *tbcharsZ = InflateString(cx, bytes, &length); 1.463 + if (!tbcharsZ) 1.464 + return nullptr; 1.465 + return AtomizeAndtake(cx, tbcharsZ, length, ib); 1.466 +} 1.467 + 1.468 +JSAtom * 1.469 +js::AtomizeChars(ExclusiveContext *cx, const jschar *chars, size_t length, InternBehavior ib) 1.470 +{ 1.471 + CHECK_REQUEST(cx); 1.472 + 1.473 + if (!JSString::validateLength(cx, length)) 1.474 + return nullptr; 1.475 + 1.476 + return AtomizeAndCopyChars(cx, chars, length, ib); 1.477 +} 1.478 + 1.479 +bool 1.480 +js::IndexToIdSlow(ExclusiveContext *cx, uint32_t index, MutableHandleId idp) 1.481 +{ 1.482 + JS_ASSERT(index > JSID_INT_MAX); 1.483 + 1.484 + jschar buf[UINT32_CHAR_BUFFER_LENGTH]; 1.485 + RangedPtr<jschar> end(ArrayEnd(buf), buf, ArrayEnd(buf)); 1.486 + RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end); 1.487 + 1.488 + JSAtom *atom = AtomizeChars(cx, start.get(), end - start); 1.489 + if (!atom) 1.490 + return false; 1.491 + 1.492 + idp.set(JSID_FROM_BITS((size_t)atom)); 1.493 + return true; 1.494 +} 1.495 + 1.496 +template <AllowGC allowGC> 1.497 +static JSAtom * 1.498 +ToAtomSlow(ExclusiveContext *cx, typename MaybeRooted<Value, allowGC>::HandleType arg) 1.499 +{ 1.500 + JS_ASSERT(!arg.isString()); 1.501 + 1.502 + Value v = arg; 1.503 + if (!v.isPrimitive()) { 1.504 + if (!cx->shouldBeJSContext() || !allowGC) 1.505 + return nullptr; 1.506 + RootedValue v2(cx, v); 1.507 + if (!ToPrimitive(cx->asJSContext(), JSTYPE_STRING, &v2)) 1.508 + return nullptr; 1.509 + v = v2; 1.510 + } 1.511 + 1.512 + if (v.isString()) 1.513 + return AtomizeString(cx, v.toString()); 1.514 + if (v.isInt32()) 1.515 + return Int32ToAtom(cx, v.toInt32()); 1.516 + if (v.isDouble()) 1.517 + return NumberToAtom(cx, v.toDouble()); 1.518 + if (v.isBoolean()) 1.519 + return v.toBoolean() ? cx->names().true_ : cx->names().false_; 1.520 + if (v.isNull()) 1.521 + return cx->names().null; 1.522 + return cx->names().undefined; 1.523 +} 1.524 + 1.525 +template <AllowGC allowGC> 1.526 +JSAtom * 1.527 +js::ToAtom(ExclusiveContext *cx, typename MaybeRooted<Value, allowGC>::HandleType v) 1.528 +{ 1.529 + if (!v.isString()) 1.530 + return ToAtomSlow<allowGC>(cx, v); 1.531 + 1.532 + JSString *str = v.toString(); 1.533 + if (str->isAtom()) 1.534 + return &str->asAtom(); 1.535 + 1.536 + return AtomizeString(cx, str); 1.537 +} 1.538 + 1.539 +template JSAtom * 1.540 +js::ToAtom<CanGC>(ExclusiveContext *cx, HandleValue v); 1.541 + 1.542 +template JSAtom * 1.543 +js::ToAtom<NoGC>(ExclusiveContext *cx, Value v); 1.544 + 1.545 +template<XDRMode mode> 1.546 +bool 1.547 +js::XDRAtom(XDRState<mode> *xdr, MutableHandleAtom atomp) 1.548 +{ 1.549 + if (mode == XDR_ENCODE) { 1.550 + uint32_t nchars = atomp->length(); 1.551 + if (!xdr->codeUint32(&nchars)) 1.552 + return false; 1.553 + 1.554 + jschar *chars = const_cast<jschar *>(atomp->getChars(xdr->cx())); 1.555 + if (!chars) 1.556 + return false; 1.557 + 1.558 + return xdr->codeChars(chars, nchars); 1.559 + } 1.560 + 1.561 + /* Avoid JSString allocation for already existing atoms. See bug 321985. */ 1.562 + uint32_t nchars; 1.563 + if (!xdr->codeUint32(&nchars)) 1.564 + return false; 1.565 + 1.566 + JSContext *cx = xdr->cx(); 1.567 + JSAtom *atom; 1.568 +#if IS_LITTLE_ENDIAN 1.569 + /* Directly access the little endian chars in the XDR buffer. */ 1.570 + const jschar *chars = reinterpret_cast<const jschar *>(xdr->buf.read(nchars * sizeof(jschar))); 1.571 + atom = AtomizeChars(cx, chars, nchars); 1.572 +#else 1.573 + /* 1.574 + * We must copy chars to a temporary buffer to convert between little and 1.575 + * big endian data. 1.576 + */ 1.577 + jschar *chars; 1.578 + jschar stackChars[256]; 1.579 + if (nchars <= ArrayLength(stackChars)) { 1.580 + chars = stackChars; 1.581 + } else { 1.582 + /* 1.583 + * This is very uncommon. Don't use the tempLifoAlloc arena for this as 1.584 + * most allocations here will be bigger than tempLifoAlloc's default 1.585 + * chunk size. 1.586 + */ 1.587 + chars = cx->runtime()->pod_malloc<jschar>(nchars); 1.588 + if (!chars) 1.589 + return false; 1.590 + } 1.591 + 1.592 + JS_ALWAYS_TRUE(xdr->codeChars(chars, nchars)); 1.593 + atom = AtomizeChars(cx, chars, nchars); 1.594 + if (chars != stackChars) 1.595 + js_free(chars); 1.596 +#endif /* !IS_LITTLE_ENDIAN */ 1.597 + 1.598 + if (!atom) 1.599 + return false; 1.600 + atomp.set(atom); 1.601 + return true; 1.602 +} 1.603 + 1.604 +template bool 1.605 +js::XDRAtom(XDRState<XDR_ENCODE> *xdr, MutableHandleAtom atomp); 1.606 + 1.607 +template bool 1.608 +js::XDRAtom(XDRState<XDR_DECODE> *xdr, MutableHandleAtom atomp); 1.609 +