michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_Id_h michael@0: #define js_Id_h michael@0: michael@0: // A jsid is an identifier for a property or method of an object which is michael@0: // either a 31-bit signed integer, interned string or object. michael@0: // michael@0: // Also, there is an additional jsid value, JSID_VOID, which does not occur in michael@0: // JS scripts but may be used to indicate the absence of a valid jsid. A void michael@0: // jsid is not a valid id and only arises as an exceptional API return value, michael@0: // such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI michael@0: // entry points expecting a jsid and do not need to handle JSID_VOID in hooks michael@0: // receiving a jsid except when explicitly noted in the API contract. michael@0: // michael@0: // A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or michael@0: // JS_IdToValue must be used instead. michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include "jstypes.h" michael@0: michael@0: #include "js/HeapAPI.h" michael@0: #include "js/RootingAPI.h" michael@0: #include "js/TypeDecls.h" michael@0: #include "js/Utility.h" michael@0: michael@0: struct jsid michael@0: { michael@0: size_t asBits; michael@0: bool operator==(jsid rhs) const { return asBits == rhs.asBits; } michael@0: bool operator!=(jsid rhs) const { return asBits != rhs.asBits; } michael@0: }; michael@0: #define JSID_BITS(id) (id.asBits) michael@0: michael@0: #define JSID_TYPE_STRING 0x0 michael@0: #define JSID_TYPE_INT 0x1 michael@0: #define JSID_TYPE_VOID 0x2 michael@0: #define JSID_TYPE_OBJECT 0x4 michael@0: #define JSID_TYPE_MASK 0x7 michael@0: michael@0: // Avoid using canonical 'id' for jsid parameters since this is a magic word in michael@0: // Objective-C++ which, apparently, wants to be able to #include jsapi.h. michael@0: #define id iden michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_STRING(jsid id) michael@0: { michael@0: return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSString * michael@0: JSID_TO_STRING(jsid id) michael@0: { michael@0: MOZ_ASSERT(JSID_IS_STRING(id)); michael@0: return (JSString *)JSID_BITS(id); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_ZERO(jsid id) michael@0: { michael@0: return JSID_BITS(id) == 0; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_INT(jsid id) michael@0: { michael@0: return !!(JSID_BITS(id) & JSID_TYPE_INT); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE int32_t michael@0: JSID_TO_INT(jsid id) michael@0: { michael@0: MOZ_ASSERT(JSID_IS_INT(id)); michael@0: return ((uint32_t)JSID_BITS(id)) >> 1; michael@0: } michael@0: michael@0: #define JSID_INT_MIN 0 michael@0: #define JSID_INT_MAX INT32_MAX michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: INT_FITS_IN_JSID(int32_t i) michael@0: { michael@0: return i >= 0; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE jsid michael@0: INT_TO_JSID(int32_t i) michael@0: { michael@0: jsid id; michael@0: MOZ_ASSERT(INT_FITS_IN_JSID(i)); michael@0: JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT); michael@0: return id; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_OBJECT(jsid id) michael@0: { michael@0: return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT && michael@0: (size_t)JSID_BITS(id) != JSID_TYPE_OBJECT; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSObject * michael@0: JSID_TO_OBJECT(jsid id) michael@0: { michael@0: MOZ_ASSERT(JSID_IS_OBJECT(id)); michael@0: return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE jsid michael@0: OBJECT_TO_JSID(JSObject *obj) michael@0: { michael@0: jsid id; michael@0: MOZ_ASSERT(obj != nullptr); michael@0: MOZ_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0); michael@0: JS_ASSERT(!js::gc::IsInsideNursery(js::gc::GetGCThingRuntime(obj), obj)); michael@0: JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT); michael@0: return id; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_GCTHING(jsid id) michael@0: { michael@0: return JSID_IS_STRING(id) || JSID_IS_OBJECT(id); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE void * michael@0: JSID_TO_GCTHING(jsid id) michael@0: { michael@0: return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_VOID(const jsid id) michael@0: { michael@0: MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, michael@0: JSID_BITS(id) == JSID_TYPE_VOID); michael@0: return ((size_t)JSID_BITS(id) == JSID_TYPE_VOID); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_EMPTY(const jsid id) michael@0: { michael@0: return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT); michael@0: } michael@0: michael@0: #undef id michael@0: michael@0: extern JS_PUBLIC_DATA(const jsid) JSID_VOID; michael@0: extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY; michael@0: michael@0: extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; michael@0: extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; michael@0: michael@0: namespace js { michael@0: michael@0: inline bool michael@0: IsPoisonedId(jsid iden) michael@0: { michael@0: if (JSID_IS_STRING(iden)) michael@0: return JS::IsPoisonedPtr(JSID_TO_STRING(iden)); michael@0: if (JSID_IS_OBJECT(iden)) michael@0: return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden)); michael@0: return false; michael@0: } michael@0: michael@0: template <> struct GCMethods michael@0: { michael@0: static jsid initial() { return JSID_VOID; } michael@0: static ThingRootKind kind() { return THING_ROOT_ID; } michael@0: static bool poisoned(jsid id) { return IsPoisonedId(id); } michael@0: static bool needsPostBarrier(jsid id) { return false; } michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(jsid *idp) {} michael@0: static void relocate(jsid *idp) {} michael@0: #endif michael@0: }; michael@0: michael@0: } michael@0: michael@0: #endif /* js_Id_h */