| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jsatominlines_h |
| #define jsatominlines_h |
| |
| #include "mozilla/PodOperations.h" |
| #include "mozilla/RangedPtr.h" |
| |
| #include "jsatom.h" |
| #include "jscntxt.h" |
| #include "jsnum.h" |
| #include "jsobj.h" |
| #include "jsstr.h" |
| #include "gc/Barrier.h" |
| #include "vm/String.h" |
| |
| inline JSAtom * |
| js::AtomStateEntry::asPtr() const |
| { |
| JS_ASSERT(bits != 0); |
| JSAtom *atom = reinterpret_cast<JSAtom *>(bits & NO_TAG_MASK); |
| JSString::readBarrier(atom); |
| return atom; |
| } |
| |
| namespace js { |
| |
| inline jsid |
| AtomToId(JSAtom *atom) |
| { |
| JS_STATIC_ASSERT(JSID_INT_MIN == 0); |
| |
| uint32_t index; |
| if (atom->isIndex(&index) && index <= JSID_INT_MAX) |
| return INT_TO_JSID(int32_t(index)); |
| |
| return JSID_FROM_BITS(size_t(atom)); |
| } |
| |
| template <AllowGC allowGC> |
| inline bool |
| ValueToId(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v, |
| typename MaybeRooted<jsid, allowGC>::MutableHandleType idp) |
| { |
| int32_t i; |
| if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { |
| idp.set(INT_TO_JSID(i)); |
| return true; |
| } |
| |
| JSAtom *atom = ToAtom<allowGC>(cx, v); |
| if (!atom) |
| return false; |
| |
| idp.set(AtomToId(atom)); |
| return true; |
| } |
| |
| /* |
| * Write out character representing |index| to the memory just before |end|. |
| * Thus |*end| is not touched, but |end[-1]| and earlier are modified as |
| * appropriate. There must be at least js::UINT32_CHAR_BUFFER_LENGTH elements |
| * before |end| to avoid buffer underflow. The start of the characters written |
| * is returned and is necessarily before |end|. |
| */ |
| template <typename T> |
| inline mozilla::RangedPtr<T> |
| BackfillIndexInCharBuffer(uint32_t index, mozilla::RangedPtr<T> end) |
| { |
| #ifdef DEBUG |
| /* |
| * Assert that the buffer we're filling will hold as many characters as we |
| * could write out, by dereferencing the index that would hold the most |
| * significant digit. |
| */ |
| (void) *(end - UINT32_CHAR_BUFFER_LENGTH); |
| #endif |
| |
| do { |
| uint32_t next = index / 10, digit = index % 10; |
| *--end = '0' + digit; |
| index = next; |
| } while (index > 0); |
| |
| return end; |
| } |
| |
| template <AllowGC allowGC> |
| bool |
| IndexToIdSlow(JSContext *cx, uint32_t index, |
| typename MaybeRooted<jsid, allowGC>::MutableHandleType idp); |
| |
| inline bool |
| IndexToId(JSContext *cx, uint32_t index, MutableHandleId idp) |
| { |
| MaybeCheckStackRoots(cx); |
| |
| if (index <= JSID_INT_MAX) { |
| idp.set(INT_TO_JSID(index)); |
| return true; |
| } |
| |
| return IndexToIdSlow<CanGC>(cx, index, idp); |
| } |
| |
| inline bool |
| IndexToIdNoGC(JSContext *cx, uint32_t index, jsid *idp) |
| { |
| if (index <= JSID_INT_MAX) { |
| *idp = INT_TO_JSID(index); |
| return true; |
| } |
| |
| return IndexToIdSlow<NoGC>(cx, index, idp); |
| } |
| |
| static JS_ALWAYS_INLINE JSFlatString * |
| IdToString(JSContext *cx, jsid id) |
| { |
| if (JSID_IS_STRING(id)) |
| return JSID_TO_ATOM(id); |
| |
| if (JS_LIKELY(JSID_IS_INT(id))) |
| return Int32ToString<CanGC>(cx, JSID_TO_INT(id)); |
| |
| RootedValue idv(cx, IdToValue(id)); |
| JSString *str = ToStringSlow<CanGC>(cx, idv); |
| if (!str) |
| return NULL; |
| |
| return str->ensureFlat(cx); |
| } |
| |
| inline |
| AtomHasher::Lookup::Lookup(const JSAtom *atom) |
| : chars(atom->chars()), length(atom->length()), atom(atom) |
| {} |
| |
| inline bool |
| AtomHasher::match(const AtomStateEntry &entry, const Lookup &lookup) |
| { |
| JSAtom *key = entry.asPtr(); |
| if (lookup.atom) |
| return lookup.atom == key; |
| if (key->length() != lookup.length) |
| return false; |
| return mozilla::PodEqual(key->chars(), lookup.chars, lookup.length); |
| } |
| |
| inline Handle<PropertyName*> |
| TypeName(JSType type, JSRuntime *rt) |
| { |
| JS_ASSERT(type < JSTYPE_LIMIT); |
| JS_STATIC_ASSERT(offsetof(JSAtomState, undefined) + |
| JSTYPE_LIMIT * sizeof(FixedHeapPtr<PropertyName>) <= |
| sizeof(JSAtomState)); |
| JS_STATIC_ASSERT(JSTYPE_VOID == 0); |
| return (&rt->atomState.undefined)[type]; |
| } |
| |
| inline Handle<PropertyName*> |
| TypeName(JSType type, JSContext *cx) |
| { |
| return TypeName(type, cx->runtime()); |
| } |
| |
| inline Handle<PropertyName*> |
| ClassName(JSProtoKey key, JSContext *cx) |
| { |
| JS_ASSERT(key < JSProto_LIMIT); |
| JS_STATIC_ASSERT(offsetof(JSAtomState, Null) + |
| JSProto_LIMIT * sizeof(FixedHeapPtr<PropertyName>) <= |
| sizeof(JSAtomState)); |
| JS_STATIC_ASSERT(JSProto_Null == 0); |
| return (&cx->runtime()->atomState.Null)[key]; |
| } |
| |
| } // namespace js |
| |
| #endif /* jsatominlines_h */ |