gecko/js/public/Id.h

196 lines
5.2 KiB
C++

/* -*- 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 js_Id_h
#define js_Id_h
// A jsid is an identifier for a property or method of an object which is
// either a 31-bit signed integer, interned string or object.
//
// Also, there is an additional jsid value, JSID_VOID, which does not occur in
// JS scripts but may be used to indicate the absence of a valid jsid. A void
// jsid is not a valid id and only arises as an exceptional API return value,
// such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
// entry points expecting a jsid and do not need to handle JSID_VOID in hooks
// receiving a jsid except when explicitly noted in the API contract.
//
// A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
// JS_IdToValue must be used instead.
#include "jstypes.h"
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
struct jsid
{
size_t asBits;
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
bool operator!=(jsid rhs) const { return asBits != rhs.asBits; }
};
#define JSID_BITS(id) (id.asBits)
#define JSID_TYPE_STRING 0x0
#define JSID_TYPE_INT 0x1
#define JSID_TYPE_VOID 0x2
#define JSID_TYPE_SYMBOL 0x4
#define JSID_TYPE_MASK 0x7
// Avoid using canonical 'id' for jsid parameters since this is a magic word in
// Objective-C++ which, apparently, wants to be able to #include jsapi.h.
#define id iden
static MOZ_ALWAYS_INLINE bool
JSID_IS_STRING(jsid id)
{
return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
}
static MOZ_ALWAYS_INLINE JSString *
JSID_TO_STRING(jsid id)
{
MOZ_ASSERT(JSID_IS_STRING(id));
return (JSString *)JSID_BITS(id);
}
/*
* Only JSStrings that have been interned via the JSAPI can be turned into
* jsids by API clients.
*
* N.B. if a jsid is backed by a string which has not been interned, that
* string must be appropriately rooted to avoid being collected by the GC.
*/
JS_PUBLIC_API(jsid)
INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str);
static MOZ_ALWAYS_INLINE bool
JSID_IS_ZERO(jsid id)
{
return JSID_BITS(id) == 0;
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_INT(jsid id)
{
return !!(JSID_BITS(id) & JSID_TYPE_INT);
}
static MOZ_ALWAYS_INLINE int32_t
JSID_TO_INT(jsid id)
{
MOZ_ASSERT(JSID_IS_INT(id));
return ((uint32_t)JSID_BITS(id)) >> 1;
}
#define JSID_INT_MIN 0
#define JSID_INT_MAX INT32_MAX
static MOZ_ALWAYS_INLINE bool
INT_FITS_IN_JSID(int32_t i)
{
return i >= 0;
}
static MOZ_ALWAYS_INLINE jsid
INT_TO_JSID(int32_t i)
{
jsid id;
MOZ_ASSERT(INT_FITS_IN_JSID(i));
JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT);
return id;
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_SYMBOL(jsid id)
{
return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL &&
JSID_BITS(id) != JSID_TYPE_SYMBOL;
}
static MOZ_ALWAYS_INLINE JS::Symbol *
JSID_TO_SYMBOL(jsid id)
{
MOZ_ASSERT(JSID_IS_SYMBOL(id));
return (JS::Symbol *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
}
static MOZ_ALWAYS_INLINE jsid
SYMBOL_TO_JSID(JS::Symbol *sym)
{
jsid id;
MOZ_ASSERT(sym != nullptr);
MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0);
MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell *>(sym)));
MOZ_ASSERT(!JS::IsPoisonedPtr(sym));
JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL);
return id;
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_GCTHING(jsid id)
{
return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id);
}
static MOZ_ALWAYS_INLINE JS::GCCellPtr
JSID_TO_GCTHING(jsid id)
{
void *thing = (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
if (JSID_IS_STRING(id))
return JS::GCCellPtr(thing, JSTRACE_STRING);
MOZ_ASSERT(JSID_IS_SYMBOL(id));
return JS::GCCellPtr(thing, JSTRACE_SYMBOL);
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_VOID(const jsid id)
{
MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID,
JSID_BITS(id) == JSID_TYPE_VOID);
return (size_t)JSID_BITS(id) == JSID_TYPE_VOID;
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_EMPTY(const jsid id)
{
return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL;
}
extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE;
extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE;
namespace js {
inline bool
IsPoisonedId(jsid id)
{
if (JSID_IS_STRING(id))
return JS::IsPoisonedPtr(JSID_TO_STRING(id));
if (JSID_IS_SYMBOL(id))
return JS::IsPoisonedPtr(JSID_TO_SYMBOL(id));
return false;
}
template <> struct GCMethods<jsid>
{
static jsid initial() { return JSID_VOID; }
static bool poisoned(jsid id) { return IsPoisonedId(id); }
static bool needsPostBarrier(jsid id) { return false; }
static void postBarrier(jsid *idp) {}
static void relocate(jsid *idp) {}
};
#undef id
}
#endif /* js_Id_h */