Bug 909178 (part 1) - Move |jsid| from jsapi.h into js/Id.h. r=luke.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 21 Aug 2013 22:26:56 -0700
changeset 144443 7f8e99aec954ac5a731b942a5cc9be2060bf6350
parent 144442 8773a32c8f39f668101d7f847fdd0b13add14fdc
child 144444 f8fec7c369d122af724ab6635ea81cd09f75a836
push id25162
push useremorley@mozilla.com
push dateTue, 27 Aug 2013 14:16:53 +0000
treeherdermozilla-central@f57a6179a085 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs909178
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 909178 (part 1) - Move |jsid| from jsapi.h into js/Id.h. r=luke.
dom/base/nsDOMClassInfo.h
dom/base/nsWrapperCache.h
js/public/Id.h
js/public/IdForward.h
js/public/RootingAPI.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jspubtd.h
js/src/moz.build
js/src/vm/Id.cpp
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -6,16 +6,17 @@
 
 #ifndef nsDOMClassInfo_h___
 #define nsDOMClassInfo_h___
 
 #include "mozilla/Attributes.h"
 #include "nsIXPCScriptable.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMScriptObjectFactory.h"
+#include "js/Id.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 class nsContentList;
 class nsDocument;
 class nsGlobalWindow;
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -3,16 +3,17 @@
  * 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 nsWrapperCache_h___
 #define nsWrapperCache_h___
 
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Assertions.h"
+#include "js/Id.h"          // must come before js/RootingAPI.h
 #include "js/Value.h"       // must come before js/RootingAPI.h
 #include "js/RootingAPI.h"
 
 struct JSTracer;
 class JSObject;
 struct JSContext;
 class XPCWrappedNativeScope;
 
new file mode 100644
--- /dev/null
+++ b/js/public/Id.h
@@ -0,0 +1,150 @@
+/* -*- 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
+
+#include "jstypes.h"
+
+#include "js/IdForward.h"
+#include "js/Utility.h"
+
+class JSObject;
+class JSString;
+
+#ifdef JS_USE_JSID_STRUCT_TYPES
+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)
+#else
+# define JSID_BITS(id) (id)
+#endif
+
+#define JSID_TYPE_STRING                 0x0
+#define JSID_TYPE_INT                    0x1
+#define JSID_TYPE_VOID                   0x2
+#define JSID_TYPE_OBJECT                 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 JS_ALWAYS_INLINE bool
+JSID_IS_STRING(jsid id)
+{
+    return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
+}
+
+static JS_ALWAYS_INLINE JSString *
+JSID_TO_STRING(jsid id)
+{
+    JS_ASSERT(JSID_IS_STRING(id));
+    return (JSString *)JSID_BITS(id);
+}
+
+static JS_ALWAYS_INLINE bool
+JSID_IS_ZERO(jsid id)
+{
+    return JSID_BITS(id) == 0;
+}
+
+static JS_ALWAYS_INLINE bool
+JSID_IS_INT(jsid id)
+{
+    return !!(JSID_BITS(id) & JSID_TYPE_INT);
+}
+
+static JS_ALWAYS_INLINE int32_t
+JSID_TO_INT(jsid id)
+{
+    JS_ASSERT(JSID_IS_INT(id));
+    return ((uint32_t)JSID_BITS(id)) >> 1;
+}
+
+#define JSID_INT_MIN  0
+#define JSID_INT_MAX  INT32_MAX
+
+static JS_ALWAYS_INLINE bool
+INT_FITS_IN_JSID(int32_t i)
+{
+    return i >= 0;
+}
+
+static JS_ALWAYS_INLINE jsid
+INT_TO_JSID(int32_t i)
+{
+    jsid id;
+    JS_ASSERT(INT_FITS_IN_JSID(i));
+    JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT);
+    return id;
+}
+
+static JS_ALWAYS_INLINE bool
+JSID_IS_OBJECT(jsid id)
+{
+    return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT &&
+           (size_t)JSID_BITS(id) != JSID_TYPE_OBJECT;
+}
+
+static JS_ALWAYS_INLINE JSObject *
+JSID_TO_OBJECT(jsid id)
+{
+    JS_ASSERT(JSID_IS_OBJECT(id));
+    return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
+}
+
+static JS_ALWAYS_INLINE jsid
+OBJECT_TO_JSID(JSObject *obj)
+{
+    jsid id;
+    JS_ASSERT(obj != NULL);
+    JS_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
+    JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
+    return id;
+}
+
+static JS_ALWAYS_INLINE bool
+JSID_IS_GCTHING(jsid id)
+{
+    return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
+}
+
+static JS_ALWAYS_INLINE void *
+JSID_TO_GCTHING(jsid id)
+{
+    return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
+}
+
+static JS_ALWAYS_INLINE bool
+JSID_IS_VOID(const jsid id)
+{
+    JS_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 JS_ALWAYS_INLINE bool
+JSID_IS_EMPTY(const jsid id)
+{
+    return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT);
+}
+
+#undef id
+
+#ifdef JS_USE_JSID_STRUCT_TYPES
+extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
+extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
+#else
+# define JSID_VOID ((jsid)JSID_TYPE_VOID)
+# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
+#endif
+
+#endif /* js_Id_h */
new file mode 100644
--- /dev/null
+++ b/js/public/IdForward.h
@@ -0,0 +1,55 @@
+/* -*- 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_IdForward_h
+#define js_IdForward_h
+
+#include <stddef.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.
+//
+// In release builds, jsid is defined to be an integral type. This
+// prevents many bugs from being caught at compile time. E.g.:
+//
+//  jsid id = ...
+//  if (id)             // error
+//    ...
+//
+//  size_t n = id;      // error
+//
+// To catch more errors, jsid is given a struct type in C++ debug builds.
+// Struct assignment and (in C++) operator== allow correct code to be mostly
+// oblivious to the change. This feature can be explicitly disabled in debug
+// builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES.
+//
+// Note: if jsid was always a struct, we could just forward declare it in
+// places where its declaration is needed.  But the fact that it's a typedef in
+// non-debug builds prevents that.  So we have this file, which is morally
+// equivalent to a forward declaration, and should be included by any file that
+// uses jsid but doesn't need its definition.
+
+#if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
+# define JS_USE_JSID_STRUCT_TYPES
+#endif
+
+#ifdef JS_USE_JSID_STRUCT_TYPES
+struct jsid;
+#else
+typedef ptrdiff_t jsid;
+#endif
+
+#endif /* js_IdForward_h */
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -7,16 +7,17 @@
 #ifndef js_RootingAPI_h
 #define js_RootingAPI_h
 
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TypeTraits.h"
 
 #include "jspubtd.h"
 
+#include "js/IdForward.h"
 #include "js/Utility.h"
 
 /*
  * Moving GC Stack Rooting
  *
  * A moving GC may change the physical location of GC allocated things, even
  * when they are rooted, updating all pointers to the thing to refer to its new
  * location. The GC must therefore know about all live pointers to a thing,
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -118,21 +118,16 @@ JS::detail::CallMethodIfWrapped(JSContex
 }
 
 #ifdef HAVE_VA_LIST_AS_ARRAY
 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
 #else
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
 
-#ifdef JS_USE_JSID_STRUCT_TYPES
-const jsid JSID_VOID  = { size_t(JSID_TYPE_VOID) };
-const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
-#endif
-
 const jsid voidIdValue = JSID_VOID;
 const jsid emptyIdValue = JSID_EMPTY;
 const HandleId JS::JSID_VOIDHANDLE = HandleId::fromMarkedLocation(&voidIdValue);
 const HandleId JS::JSID_EMPTYHANDLE = HandleId::fromMarkedLocation(&emptyIdValue);
 
 /* Make sure that jschar is two bytes unsigned integer */
 JS_STATIC_ASSERT((jschar)-1 > 0);
 JS_STATIC_ASSERT(sizeof(jschar) == 2);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -18,16 +18,17 @@
 #include <stdint.h>
 #include <stdio.h>
 
 #include "jsalloc.h"
 #include "jspubtd.h"
 
 #include "js/CallArgs.h"
 #include "js/HashTable.h"
+#include "js/Id.h"
 #include "js/RootingAPI.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
 /************************************************************************/
 
 namespace JS {
@@ -1155,168 +1156,29 @@ JS_NumberValue(double d)
     d = JS_CANONICALIZE_NAN(d);
     if (mozilla::DoubleIsInt32(d, &i))
         return INT_TO_JSVAL(i);
     return DOUBLE_TO_JSVAL(d);
 }
 
 /************************************************************************/
 
-/*
- * 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 jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
- * JS_IdToValue must be used instead.
- */
-
-#define JSID_TYPE_STRING                 0x0
-#define JSID_TYPE_INT                    0x1
-#define JSID_TYPE_VOID                   0x2
-#define JSID_TYPE_OBJECT                 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 JS_ALWAYS_INLINE bool
-JSID_IS_STRING(jsid id)
-{
-    return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
-}
-
-static JS_ALWAYS_INLINE JSString *
-JSID_TO_STRING(jsid id)
-{
-    JS_ASSERT(JSID_IS_STRING(id));
-    return (JSString *)JSID_BITS(id);
-}
-
-static JS_ALWAYS_INLINE bool
-JSID_IS_ZERO(jsid id)
-{
-    return JSID_BITS(id) == 0;
-}
-
 JS_PUBLIC_API(bool)
 JS_StringHasBeenInterned(JSContext *cx, JSString *str);
 
 /*
  * 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 JS_ALWAYS_INLINE bool
-JSID_IS_INT(jsid id)
-{
-    return !!(JSID_BITS(id) & JSID_TYPE_INT);
-}
-
-static JS_ALWAYS_INLINE int32_t
-JSID_TO_INT(jsid id)
-{
-    JS_ASSERT(JSID_IS_INT(id));
-    return ((uint32_t)JSID_BITS(id)) >> 1;
-}
-
-#define JSID_INT_MIN  0
-#define JSID_INT_MAX  INT32_MAX
-
-static JS_ALWAYS_INLINE bool
-INT_FITS_IN_JSID(int32_t i)
-{
-    return i >= 0;
-}
-
-static JS_ALWAYS_INLINE jsid
-INT_TO_JSID(int32_t i)
-{
-    jsid id;
-    JS_ASSERT(INT_FITS_IN_JSID(i));
-    JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT);
-    return id;
-}
-
-static JS_ALWAYS_INLINE bool
-JSID_IS_OBJECT(jsid id)
-{
-    return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT &&
-           (size_t)JSID_BITS(id) != JSID_TYPE_OBJECT;
-}
-
-static JS_ALWAYS_INLINE JSObject *
-JSID_TO_OBJECT(jsid id)
-{
-    JS_ASSERT(JSID_IS_OBJECT(id));
-    return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
-}
-
-static JS_ALWAYS_INLINE jsid
-OBJECT_TO_JSID(JSObject *obj)
-{
-    jsid id;
-    JS_ASSERT(obj != NULL);
-    JS_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
-    JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
-    return id;
-}
-
-static JS_ALWAYS_INLINE bool
-JSID_IS_GCTHING(jsid id)
-{
-    return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
-}
-
-static JS_ALWAYS_INLINE void *
-JSID_TO_GCTHING(jsid id)
-{
-    return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
-}
-
-/*
- * 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.
- */
-
-static JS_ALWAYS_INLINE bool
-JSID_IS_VOID(const jsid id)
-{
-    JS_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 JS_ALWAYS_INLINE bool
-JSID_IS_EMPTY(const jsid id)
-{
-    return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT);
-}
-
-#undef id
-
-#ifdef JS_USE_JSID_STRUCT_TYPES
-extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
-extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
-#else
-# define JSID_VOID ((jsid)JSID_TYPE_VOID)
-# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
-#endif
-
 /*
  * Returns true iff the given jsval is immune to GC and can be used across
  * multiple JSRuntimes without requiring any conversion API.
  */
 static JS_ALWAYS_INLINE bool
 JSVAL_IS_UNIVERSAL(jsval v)
 {
     return !JSVAL_IS_GCTHING(v);
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -12,16 +12,18 @@
  */
 
 #include "mozilla/PodOperations.h"
 
 #include "jsprototypes.h"
 #include "jstypes.h"
 #include "jsversion.h"  // #include here so it's seen everywhere
 
+#include "js/IdForward.h"
+
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(DEBUG)
 # define JSGC_TRACK_EXACT_ROOTS
 #endif
 
 namespace JS {
 
 /*
  * Allow headers to reference JS::Value without #including the whole jsapi.h.
@@ -39,48 +41,16 @@ class JS_PUBLIC_API(AutoGCRooter);
 
 class JS_PUBLIC_API(CompileOptions);
 class JS_PUBLIC_API(CompartmentOptions);
 
 struct Zone;
 
 } /* namespace JS */
 
-/*
- * In release builds, jsid is defined to be an integral type. This
- * prevents many bugs from being caught at compile time. E.g.:
- *
- *  jsid id = ...
- *  if (id)             // error
- *    ...
- *
- *  size_t n = id;      // error
- *
- * To catch more errors, jsid is given a struct type in C++ debug builds.
- * Struct assignment and (in C++) operator== allow correct code to be mostly
- * oblivious to the change. This feature can be explicitly disabled in debug
- * builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES.
- */
-# if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
-#  define JS_USE_JSID_STRUCT_TYPES
-# endif
-
-# ifdef JS_USE_JSID_STRUCT_TYPES
-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)
-# else  /* defined(JS_USE_JSID_STRUCT_TYPES) */
-typedef ptrdiff_t jsid;
-#  define JSID_BITS(id) (id)
-# endif  /* defined(JS_USE_JSID_STRUCT_TYPES) */
-
 #ifdef WIN32
 typedef wchar_t   jschar;
 #else
 typedef uint16_t  jschar;
 #endif
 
 /*
  * Run-time version enumeration.  For compile-time version checking, please use
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -61,16 +61,18 @@ if CONFIG['HAVE_DTRACE']:
 EXPORTS.js += [
     '../public/Anchor.h',
     '../public/CallArgs.h',
     '../public/CharacterEncoding.h',
     '../public/Date.h',
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
+    '../public/Id.h',
+    '../public/IdForward.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
     '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
     '../public/StructuredClone.h',
     '../public/Utility.h',
@@ -86,16 +88,17 @@ CPP_SOURCES += [
     'CharacterEncoding.cpp',
     'DateTime.cpp',
     'Debugger.cpp',
     'Eval.cpp',
     'ExecutableAllocator.cpp',
     'FoldConstants.cpp',
     'ForkJoin.cpp',
     'GlobalObject.cpp',
+    'Id.cpp',
     'Interpreter.cpp',
     'Intl.cpp',
     'Iteration.cpp',
     'LifoAlloc.cpp',
     'MapObject.cpp',
     'Marking.cpp',
     'Memory.cpp',
     'Module.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/vm/Id.cpp
@@ -0,0 +1,13 @@
+/* -*- 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/. */
+
+#include "js/Id.h"
+
+#ifdef JS_USE_JSID_STRUCT_TYPES
+const jsid JSID_VOID  = { size_t(JSID_TYPE_VOID) };
+const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
+#endif
+