Bug 1113379 - Convert ctypes/typedefs.h into a series of higher-order macros, for better code hygiene and to work around an incredible oddity in NetBSD's <stdint.h>. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Fri, 09 Jan 2015 02:07:39 -0800
changeset 248917 be02b84dfca41dff53ab1e54a44ce0373b19168a
parent 248916 0af503927b54c9a75db5a9192e3a5a5719bf437a
child 248918 2ba79118e686b4455ac8dafe8206bfa0358296d4
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1113379
milestone37.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 1113379 - Convert ctypes/typedefs.h into a series of higher-order macros, for better code hygiene and to work around an incredible oddity in NetBSD's <stdint.h>. r=jorendorff
js/src/ctypes/CTypes.cpp
js/src/ctypes/CTypes.h
js/src/ctypes/typedefs.h
toolkit/components/ctypes/tests/jsctypes-test.cpp
toolkit/components/ctypes/tests/jsctypes-test.h
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -1271,17 +1271,18 @@ InitTypeClasses(JSContext* cx, HandleObj
   //     * 'constructor' property === 't'
 #define DEFINE_TYPE(name, type, ffiType)                                       \
   RootedObject typeObj_##name(cx,                                              \
     CType::DefineBuiltin(cx, parent, #name, CTypeProto, CDataProto, #name,     \
       TYPE_##name, INT_TO_JSVAL(sizeof(type)),                                 \
       INT_TO_JSVAL(ffiType.alignment), &ffiType));                             \
   if (!typeObj_##name)                                                         \
     return false;
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_TYPE(DEFINE_TYPE)
+#undef DEFINE_TYPE
 
   // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
   // the same type in C.
   if (!JS_DefineProperty(cx, parent, "unsigned", typeObj_unsigned_int,
                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Alias 'ctypes.jschar' as 'ctypes.char16_t' to prevent breaking addons
@@ -1661,24 +1662,25 @@ jsvalToInteger(JSContext* cx, jsval val,
     JSObject* obj = &val.toObject();
     if (CData::IsCData(obj)) {
       JSObject* typeObj = CData::GetCType(obj);
       void* data = CData::GetData(obj);
 
       // Check whether the source type is always representable, with exact
       // precision, by the target type. If it is, convert the value.
       switch (CType::GetTypeCode(typeObj)) {
-#define DEFINE_INT_TYPE(name, fromType, ffiType)                               \
+#define INTEGER_CASE(name, fromType, ffiType)                                  \
       case TYPE_##name:                                                        \
         if (!IsAlwaysExact<IntegerType, fromType>())                           \
           return false;                                                        \
         *result = IntegerType(*static_cast<fromType*>(data));                  \
         return true;
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+      CTYPES_FOR_EACH_INT_TYPE(INTEGER_CASE)
+      CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGER_CASE)
+#undef INTEGER_CASE
       case TYPE_void_t:
       case TYPE_bool:
       case TYPE_float:
       case TYPE_double:
       case TYPE_float32_t:
       case TYPE_float64_t:
       case TYPE_char:
       case TYPE_signed_char:
@@ -1750,25 +1752,26 @@ jsvalToFloat(JSContext *cx, jsval val, F
     JSObject* obj = &val.toObject();
     if (CData::IsCData(obj)) {
       JSObject* typeObj = CData::GetCType(obj);
       void* data = CData::GetData(obj);
 
       // Check whether the source type is always representable, with exact
       // precision, by the target type. If it is, convert the value.
       switch (CType::GetTypeCode(typeObj)) {
-#define DEFINE_FLOAT_TYPE(name, fromType, ffiType)                             \
+#define NUMERIC_CASE(name, fromType, ffiType)                                  \
       case TYPE_##name:                                                        \
         if (!IsAlwaysExact<FloatType, fromType>())                             \
           return false;                                                        \
         *result = FloatType(*static_cast<fromType*>(data));                    \
         return true;
-#define DEFINE_INT_TYPE(x, y, z) DEFINE_FLOAT_TYPE(x, y, z)
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+      CTYPES_FOR_EACH_FLOAT_TYPE(NUMERIC_CASE)
+      CTYPES_FOR_EACH_INT_TYPE(NUMERIC_CASE)
+      CTYPES_FOR_EACH_WRAPPED_INT_TYPE(NUMERIC_CASE)
+#undef NUMERIC_CASE
       case TYPE_void_t:
       case TYPE_bool:
       case TYPE_char:
       case TYPE_signed_char:
       case TYPE_unsigned_char:
       case TYPE_char16_t:
       case TYPE_pointer:
       case TYPE_function:
@@ -2125,26 +2128,28 @@ ConvertToJS(JSContext* cx,
 
   switch (typeCode) {
   case TYPE_void_t:
     result.setUndefined();
     break;
   case TYPE_bool:
     result.setBoolean(*static_cast<bool*>(data));
     break;
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
+#define INT_CASE(name, type, ffiType)                                          \
   case TYPE_##name: {                                                          \
     type value = *static_cast<type*>(data);                                    \
     if (sizeof(type) < 4)                                                      \
       result.setInt32(int32_t(value));                                         \
     else                                                                       \
       result.setDouble(double(value));                                         \
     break;                                                                     \
   }
-#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
+  CTYPES_FOR_EACH_INT_TYPE(INT_CASE)
+#undef INT_CASE
+#define WRAPPED_INT_CASE(name, type, ffiType)                                  \
   case TYPE_##name: {                                                          \
     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
     uint64_t value;                                                            \
     RootedObject proto(cx);                                                    \
     if (!NumericLimits<type>::is_signed) {                                     \
       value = *static_cast<type*>(data);                                       \
       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
       proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
@@ -2160,29 +2165,34 @@ ConvertToJS(JSContext* cx,
                                                                                \
     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
       !NumericLimits<type>::is_signed);                                        \
     if (!obj)                                                                  \
       return false;                                                            \
     result.setObject(*obj);                                                    \
     break;                                                                     \
   }
-#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
+#undef WRAPPED_INT_CASE
+#define FLOAT_CASE(name, type, ffiType)                                        \
   case TYPE_##name: {                                                          \
     type value = *static_cast<type*>(data);                                    \
     result.setDouble(double(value));                                           \
     break;                                                                     \
   }
-#define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
+  CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
+#undef FLOAT_CASE
+#define CHAR_CASE(name, type, ffiType)                                         \
   case TYPE_##name:                                                            \
     /* Convert to an integer. We have no idea what character encoding to */    \
     /* use, if any. */                                                         \
     result.setInt32(*static_cast<type*>(data));                                \
     break;
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_CHAR_TYPE(CHAR_CASE)
+#undef CHAR_CASE
   case TYPE_char16_t: {
     // Convert the char16_t to a 1-character string.
     JSString* str = JS_NewUCStringCopyN(cx, static_cast<char16_t*>(data), 1);
     if (!str)
       return false;
 
     result.setString(str);
     break;
@@ -2321,36 +2331,17 @@ ImplicitConvert(JSContext* cx,
     // Do not implicitly lose bits, but allow the values 0, 1, and -0.
     // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
     bool result;
     if (!jsvalToBool(cx, val, &result))
       return TypeError(cx, "boolean", val);
     *static_cast<bool*>(buffer) = result;
     break;
   }
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
-  case TYPE_##name: {                                                          \
-    /* Do not implicitly lose bits. */                                         \
-    type result;                                                               \
-    if (!jsvalToInteger(cx, val, &result))                                     \
-      return TypeError(cx, #name, val);                                        \
-    *static_cast<type*>(buffer) = result;                                      \
-    break;                                                                     \
-  }
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
-  case TYPE_##name: {                                                          \
-    type result;                                                               \
-    if (!jsvalToFloat(cx, val, &result))                                       \
-      return TypeError(cx, #name, val);                                        \
-    *static_cast<type*>(buffer) = result;                                      \
-    break;                                                                     \
-  }
-#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR16_TYPE(name, type, ffiType)                                \
+#define CHAR16_CASE(name, type, ffiType)                                       \
   case TYPE_##name: {                                                          \
     /* Convert from a 1-character string, regardless of encoding, */           \
     /* or from an integer, provided the result fits in 'type'. */              \
     type result;                                                               \
     if (val.isString()) {                                                      \
       JSString* str = val.toString();                                          \
       if (str->length() != 1)                                                  \
         return TypeError(cx, #name, val);                                      \
@@ -2359,17 +2350,45 @@ ImplicitConvert(JSContext* cx,
         return false;                                                          \
       result = linear->latin1OrTwoByteChar(0);                                 \
     } else if (!jsvalToInteger(cx, val, &result)) {                            \
       return TypeError(cx, #name, val);                                        \
     }                                                                          \
     *static_cast<type*>(buffer) = result;                                      \
     break;                                                                     \
   }
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_CHAR16_TYPE(CHAR16_CASE)
+#undef CHAR16_CASE
+#define INTEGRAL_CASE(name, type, ffiType)                                     \
+  case TYPE_##name: {                                                          \
+    /* Do not implicitly lose bits. */                                         \
+    type result;                                                               \
+    if (!jsvalToInteger(cx, val, &result))                                     \
+      return TypeError(cx, #name, val);                                        \
+    *static_cast<type*>(buffer) = result;                                      \
+    break;                                                                     \
+  }
+  CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
+  // It's hard to believe ctypes.char16_t("f") should work yet ctypes.char("f")
+  // should not.  Ditto for ctypes.{un,}signed_char.  But this is how ctypes
+  // has always worked, so preserve these semantics, and don't switch to an
+  // algorithm similar to that in DEFINE_CHAR16_TYPE above, just yet.
+  CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
+#define FLOAT_CASE(name, type, ffiType)                                        \
+  case TYPE_##name: {                                                          \
+    type result;                                                               \
+    if (!jsvalToFloat(cx, val, &result))                                       \
+      return TypeError(cx, #name, val);                                        \
+    *static_cast<type*>(buffer) = result;                                      \
+    break;                                                                     \
+  }
+  CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
+#undef FLOAT_CASE
   case TYPE_pointer: {
     if (val.isNull()) {
       // Convert to a null pointer.
       *static_cast<void**>(buffer) = nullptr;
       break;
     }
 
     JS::Rooted<JSObject*> baseType(cx, PointerType::GetBaseType(targetType));
@@ -2702,32 +2721,33 @@ ExplicitConvert(JSContext* cx, HandleVal
 
   TypeCode type = CType::GetTypeCode(targetType);
 
   switch (type) {
   case TYPE_bool: {
     *static_cast<bool*>(buffer) = ToBoolean(val);
     break;
   }
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
+#define INTEGRAL_CASE(name, type, ffiType)                                     \
   case TYPE_##name: {                                                          \
     /* Convert numeric values with a C-style cast, and */                      \
     /* allow conversion from a base-10 or base-16 string. */                   \
     type result;                                                               \
     if (!jsvalToIntegerExplicit(val, &result) &&                               \
         (!val.isString() ||                                                    \
          !StringToInteger(cx, val.toString(), &result)))                       \
       return TypeError(cx, #name, val);                                        \
     *static_cast<type*>(buffer) = result;                                      \
     break;                                                                     \
   }
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR16_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
   case TYPE_pointer: {
     // Convert a number, Int64 object, or UInt64 object to a pointer.
     uintptr_t result;
     if (!jsvalToPtrExplicit(cx, val, &result))
       return TypeError(cx, "pointer", val);
     *static_cast<uintptr_t*>(buffer) = result;
     break;
   }
@@ -2870,19 +2890,19 @@ BuildTypeSource(JSContext* cx,
                 bool makeShort,
                 AutoString& result)
 {
   RootedObject typeObj(cx, typeObj_);
 
   // Walk the types, building up the toSource() string.
   switch (CType::GetTypeCode(typeObj)) {
   case TYPE_void_t:
-#define DEFINE_TYPE(name, type, ffiType)  \
-  case TYPE_##name:
-#include "ctypes/typedefs.h"
+#define CASE_FOR_TYPE(name, type, ffiType)  case TYPE_##name:
+  CTYPES_FOR_EACH_TYPE(CASE_FOR_TYPE)
+#undef CASE_FOR_TYPE
   {
     AppendString(result, "ctypes.");
     JSString* nameStr = CType::GetName(cx, typeObj);
     AppendString(result, nameStr);
     break;
   }
   case TYPE_pointer: {
     RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
@@ -3021,52 +3041,59 @@ BuildDataSource(JSContext* cx,
   TypeCode type = CType::GetTypeCode(typeObj);
   switch (type) {
   case TYPE_bool:
     if (*static_cast<bool*>(data))
       AppendString(result, "true");
     else
       AppendString(result, "false");
     break;
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
+#define INTEGRAL_CASE(name, type, ffiType)                                     \
   case TYPE_##name:                                                            \
     /* Serialize as a primitive decimal integer. */                            \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     break;
-#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
+  CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
+#define WRAPPED_INT_CASE(name, type, ffiType)                                  \
   case TYPE_##name:                                                            \
     /* Serialize as a wrapped decimal integer. */                              \
     if (!NumericLimits<type>::is_signed)                                       \
       AppendString(result, "ctypes.UInt64(\"");                                \
     else                                                                       \
       AppendString(result, "ctypes.Int64(\"");                                 \
                                                                                \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     AppendString(result, "\")");                                               \
     break;
-#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
+#undef WRAPPED_INT_CASE
+#define FLOAT_CASE(name, type, ffiType)                                        \
   case TYPE_##name: {                                                          \
     /* Serialize as a primitive double. */                                     \
     double fp = *static_cast<type*>(data);                                     \
     ToCStringBuf cbuf;                                                         \
     char* str = NumberToCString(cx, &cbuf, fp);                                \
     if (!str) {                                                                \
       JS_ReportOutOfMemory(cx);                                                \
       return false;                                                            \
     }                                                                          \
                                                                                \
     result.append(str, strlen(str));                                           \
     break;                                                                     \
   }
-#define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
+  CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
+#undef FLOAT_CASE
+#define CHAR_CASE(name, type, ffiType)                                         \
   case TYPE_##name:                                                            \
     /* Serialize as an integer. */                                             \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     break;
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_CHAR_TYPE(CHAR_CASE)
+#undef CHAR_CASE
   case TYPE_char16_t: {
     // Serialize as a 1-character JS string.
     JSString* str = JS_NewUCStringCopyN(cx, static_cast<char16_t*>(data), 1);
     if (!str)
       return false;
 
     // Escape characters, and quote as necessary.
     RootedValue valStr(cx, StringValue(str));
@@ -5934,28 +5961,29 @@ FunctionType::Call(JSContext* cx,
   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
 #if defined(XP_WIN)
   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
 #endif // defined(XP_WIN)
 
   // Small integer types get returned as a word-sized ffi_arg. Coerce it back
   // into the correct size for ConvertToJS.
   switch (typeCode) {
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
+#define INTEGRAL_CASE(name, type, ffiType)                                     \
   case TYPE_##name:                                                            \
     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
       ffi_arg data = *static_cast<ffi_arg*>(returnValue.mData);                \
       *static_cast<type*>(returnValue.mData) = static_cast<type>(data);        \
     }                                                                          \
     break;
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR16_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
+  CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
   default:
     break;
   }
 
   // prepare a JS object from the result
   RootedObject returnType(cx, fninfo->mReturnType);
   return ConvertToJS(cx, returnType, NullPtr(), returnValue.mData, false, true, args.rval());
 }
@@ -6206,23 +6234,23 @@ CClosure::ClosureStub(ffi_cif* cif, void
 
   // Initialize the result to zero, in case something fails. Small integer types
   // are promoted to a word-sized ffi_arg, so we must be careful to zero the
   // whole word.
   size_t rvSize = 0;
   if (cif->rtype != &ffi_type_void) {
     rvSize = cif->rtype->size;
     switch (typeCode) {
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
-    case TYPE_##name:
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR16_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+#define INTEGRAL_CASE(name, type, ffiType)  case TYPE_##name:
+    CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
       rvSize = Align(rvSize, sizeof(ffi_arg));
       break;
     default:
       break;
     }
     memset(result, 0, rvSize);
   }
 
@@ -6287,28 +6315,29 @@ CClosure::ClosureStub(ffi_cif* cif, void
 
       return;
     }
   }
 
   // Small integer types must be returned as a word-sized ffi_arg. Coerce it
   // back into the size libffi expects.
   switch (typeCode) {
-#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
+#define INTEGRAL_CASE(name, type, ffiType)                                     \
   case TYPE_##name:                                                            \
     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
       ffi_arg data = *static_cast<type*>(result);                              \
       *static_cast<ffi_arg*>(result) = data;                                   \
     }                                                                          \
     break;
-#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#define DEFINE_CHAR16_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
-#include "ctypes/typedefs.h"
+    CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
+    CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
+#undef INTEGRAL_CASE
   default:
     break;
   }
 }
 
 /*******************************************************************************
 ** CData implementation
 *******************************************************************************/
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -5,16 +5,17 @@
 
 #ifndef ctypes_CTypes_h
 #define ctypes_CTypes_h
 
 #include "ffi.h"
 #include "jsalloc.h"
 #include "prlink.h"
 
+#include "ctypes/typedefs.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 #include "vm/String.h"
 
 namespace js {
 namespace ctypes {
 
 /*******************************************************************************
@@ -219,17 +220,18 @@ enum ABICode {
   ABI_STDCALL,
   ABI_WINAPI,
   INVALID_ABI
 };
 
 enum TypeCode {
   TYPE_void_t,
 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
-#include "ctypes/typedefs.h"
+  CTYPES_FOR_EACH_TYPE(DEFINE_TYPE)
+#undef DEFINE_TYPE
   TYPE_pointer,
   TYPE_function,
   TYPE_array,
   TYPE_struct
 };
 
 // Descriptor of one field in a StructType. The name of the field is stored
 // as the key to the hash entry.
--- a/js/src/ctypes/typedefs.h
+++ b/js/src/ctypes/typedefs.h
@@ -1,59 +1,41 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* 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/. */
 
 /**
  * This header contains the builtin types available for arguments and return
- * values, representing their C counterparts. They are listed inside macros
- * that the #includer is expected to #define. Format is:
+ * values, representing their C counterparts. They are used inside higher-order
+ * macros that the user must call, providing a macro that will consume the
+ * arguments provided to it by the higher-order macro. The macros exposed are:
  *
- * DEFINE_X_TYPE(typename, ctype, ffitype)
+ *   CTYPES_FOR_EACH_BOOL_TYPE(macro)
+ *   CTYPES_FOR_EACH_CHAR_TYPE(macro)
+ *   CTYPES_FOR_EACH_CHAR16_TYPE(macro)
+ *   CTYPES_FOR_EACH_INT_TYPE(macro)
+ *   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(macro)
+ *   CTYPES_FOR_EACH_FLOAT_TYPE(macro)
+ *   CTYPES_FOR_EACH_TYPE(macro)
+ *
+ * The macro name provided to any of these macros will then be repeatedly
+ * invoked as
+ *
+ *   macro(typename, ctype, ffitype)
  *
  * where 'typename' is the name of the type constructor (accessible as
  * ctypes.typename), 'ctype' is the corresponding C type declaration (from
  * which sizeof(ctype) and templated type conversions will be derived), and
  * 'ffitype' is the ffi_type to use. (Special types, such as 'void' and the
  * pointer, array, and struct types are handled separately.)
- *
- * This header lacks a #ifndef wrapper because it is deliberately #included
- * multiple times in ctypes/CTypes.h.
  */
 
-// If we're not breaking the types out, combine them together under one
-// DEFINE_TYPE macro. Otherwise, turn off whichever ones we're not using.
-#if defined(DEFINE_TYPE)
-#  define DEFINE_CHAR_TYPE(x, y, z)         DEFINE_TYPE(x, y, z)
-#  define DEFINE_CHAR16_TYPE(x, y, z)       DEFINE_TYPE(x, y, z)
-#  define DEFINE_BOOL_TYPE(x, y, z)         DEFINE_TYPE(x, y, z)
-#  define DEFINE_INT_TYPE(x, y, z)          DEFINE_TYPE(x, y, z)
-#  define DEFINE_WRAPPED_INT_TYPE(x, y, z)  DEFINE_TYPE(x, y, z)
-#  define DEFINE_FLOAT_TYPE(x, y, z)        DEFINE_TYPE(x, y, z)
-#else
-#  ifndef DEFINE_BOOL_TYPE
-#    define DEFINE_BOOL_TYPE(x, y, z)
-#  endif
-#  ifndef DEFINE_CHAR_TYPE
-#    define DEFINE_CHAR_TYPE(x, y, z)
-#  endif
-#  ifndef DEFINE_CHAR16_TYPE
-#    define DEFINE_CHAR16_TYPE(x, y, z)
-#  endif
-#  ifndef DEFINE_INT_TYPE
-#    define DEFINE_INT_TYPE(x, y, z)
-#  endif
-#  ifndef DEFINE_WRAPPED_INT_TYPE
-#    define DEFINE_WRAPPED_INT_TYPE(x, y, z)
-#  endif
-#  ifndef DEFINE_FLOAT_TYPE
-#    define DEFINE_FLOAT_TYPE(x, y, z)
-#  endif
-#endif
+#ifndef ctypes_typedefs_h
+#define  ctypes_typedefs_h
 
 // MSVC doesn't have ssize_t. Help it along a little.
 #ifdef HAVE_SSIZE_T
 #define CTYPES_SSIZE_T ssize_t
 #else
 #define CTYPES_SSIZE_T intptr_t
 #endif
 
@@ -66,57 +48,59 @@
 #define CTYPES_FFI_LONG      (sizeof(long)      == 4 ? ffi_type_sint32 : ffi_type_sint64)
 #define CTYPES_FFI_ULONG     (sizeof(long)      == 4 ? ffi_type_uint32 : ffi_type_uint64)
 #define CTYPES_FFI_SIZE_T    (sizeof(size_t)    == 4 ? ffi_type_uint32 : ffi_type_uint64)
 #define CTYPES_FFI_SSIZE_T   (sizeof(size_t)    == 4 ? ffi_type_sint32 : ffi_type_sint64)
 #define CTYPES_FFI_OFF_T     (sizeof(off_t)     == 4 ? ffi_type_sint32 : ffi_type_sint64)
 #define CTYPES_FFI_INTPTR_T  (sizeof(uintptr_t) == 4 ? ffi_type_sint32 : ffi_type_sint64)
 #define CTYPES_FFI_UINTPTR_T (sizeof(uintptr_t) == 4 ? ffi_type_uint32 : ffi_type_uint64)
 
-// The meat.
-DEFINE_BOOL_TYPE       (bool,               bool,               CTYPES_FFI_BOOL)
-DEFINE_INT_TYPE        (int8_t,             int8_t,             ffi_type_sint8)
-DEFINE_INT_TYPE        (int16_t,            int16_t,            ffi_type_sint16)
-DEFINE_INT_TYPE        (int32_t,            int32_t,            ffi_type_sint32)
-DEFINE_INT_TYPE        (uint8_t,            uint8_t,            ffi_type_uint8)
-DEFINE_INT_TYPE        (uint16_t,           uint16_t,           ffi_type_uint16)
-DEFINE_INT_TYPE        (uint32_t,           uint32_t,           ffi_type_uint32)
-DEFINE_INT_TYPE        (short,              short,              ffi_type_sint16)
-DEFINE_INT_TYPE        (unsigned_short,     unsigned short,     ffi_type_uint16)
-DEFINE_INT_TYPE        (int,                int,                ffi_type_sint32)
-DEFINE_INT_TYPE        (unsigned_int,       unsigned int,       ffi_type_uint32)
-DEFINE_WRAPPED_INT_TYPE(int64_t,            int64_t,            ffi_type_sint64)
-DEFINE_WRAPPED_INT_TYPE(uint64_t,           uint64_t,           ffi_type_uint64)
-DEFINE_WRAPPED_INT_TYPE(long,               long,               CTYPES_FFI_LONG)
-DEFINE_WRAPPED_INT_TYPE(unsigned_long,      unsigned long,      CTYPES_FFI_ULONG)
-DEFINE_WRAPPED_INT_TYPE(long_long,          long long,          ffi_type_sint64)
-DEFINE_WRAPPED_INT_TYPE(unsigned_long_long, unsigned long long, ffi_type_uint64)
-DEFINE_WRAPPED_INT_TYPE(size_t,             size_t,             CTYPES_FFI_SIZE_T)
-DEFINE_WRAPPED_INT_TYPE(ssize_t,            CTYPES_SSIZE_T,     CTYPES_FFI_SSIZE_T)
-DEFINE_WRAPPED_INT_TYPE(off_t,              off_t,              CTYPES_FFI_OFF_T)
-DEFINE_WRAPPED_INT_TYPE(intptr_t,           intptr_t,           CTYPES_FFI_INTPTR_T)
-DEFINE_WRAPPED_INT_TYPE(uintptr_t,          uintptr_t,          CTYPES_FFI_UINTPTR_T)
-DEFINE_FLOAT_TYPE      (float32_t,          float,              ffi_type_float)
-DEFINE_FLOAT_TYPE      (float64_t,          double,             ffi_type_double)
-DEFINE_FLOAT_TYPE      (float,              float,              ffi_type_float)
-DEFINE_FLOAT_TYPE      (double,             double,             ffi_type_double)
-DEFINE_CHAR_TYPE       (char,               char,               ffi_type_uint8)
-DEFINE_CHAR_TYPE       (signed_char,        signed char,        ffi_type_sint8)
-DEFINE_CHAR_TYPE       (unsigned_char,      unsigned char,      ffi_type_uint8)
-DEFINE_CHAR16_TYPE     (char16_t,           char16_t,           ffi_type_uint16)
+#define CTYPES_FOR_EACH_BOOL_TYPE(macro) \
+  macro(bool,               bool,               CTYPES_FFI_BOOL)
+
+#define CTYPES_FOR_EACH_INT_TYPE(macro) \
+  macro(int8_t,             int8_t,             ffi_type_sint8) \
+  macro(int16_t,            int16_t,            ffi_type_sint16) \
+  macro(int32_t,            int32_t,            ffi_type_sint32) \
+  macro(uint8_t,            uint8_t,            ffi_type_uint8) \
+  macro(uint16_t,           uint16_t,           ffi_type_uint16) \
+  macro(uint32_t,           uint32_t,           ffi_type_uint32) \
+  macro(short,              short,              ffi_type_sint16) \
+  macro(unsigned_short,     unsigned short,     ffi_type_uint16) \
+  macro(int,                int,                ffi_type_sint32) \
+  macro(unsigned_int,       unsigned int,       ffi_type_uint32)
 
-#undef CTYPES_SSIZE_T
-#undef CTYPES_FFI_BOOL
-#undef CTYPES_FFI_LONG
-#undef CTYPES_FFI_ULONG
-#undef CTYPES_FFI_SIZE_T
-#undef CTYPES_FFI_SSIZE_T
-#undef CTYPES_FFI_INTPTR_T
-#undef CTYPES_FFI_UINTPTR_T
+#define CTYPES_FOR_EACH_WRAPPED_INT_TYPE(macro) \
+  macro(int64_t,            int64_t,            ffi_type_sint64) \
+  macro(uint64_t,           uint64_t,           ffi_type_uint64) \
+  macro(long,               long,               CTYPES_FFI_LONG) \
+  macro(unsigned_long,      unsigned long,      CTYPES_FFI_ULONG) \
+  macro(long_long,          long long,          ffi_type_sint64) \
+  macro(unsigned_long_long, unsigned long long, ffi_type_uint64) \
+  macro(size_t,             size_t,             CTYPES_FFI_SIZE_T) \
+  macro(ssize_t,            CTYPES_SSIZE_T,     CTYPES_FFI_SSIZE_T) \
+  macro(off_t,              off_t,              CTYPES_FFI_OFF_T) \
+  macro(intptr_t,           intptr_t,           CTYPES_FFI_INTPTR_T) \
+  macro(uintptr_t,          uintptr_t,          CTYPES_FFI_UINTPTR_T)
 
-#undef DEFINE_TYPE
-#undef DEFINE_CHAR_TYPE
-#undef DEFINE_CHAR16_TYPE
-#undef DEFINE_BOOL_TYPE
-#undef DEFINE_INT_TYPE
-#undef DEFINE_WRAPPED_INT_TYPE
-#undef DEFINE_FLOAT_TYPE
+#define CTYPES_FOR_EACH_FLOAT_TYPE(macro) \
+  macro(float32_t,          float,              ffi_type_float) \
+  macro(float64_t,          double,             ffi_type_double) \
+  macro(float,              float,              ffi_type_float) \
+  macro(double,             double,             ffi_type_double)
+
+#define CTYPES_FOR_EACH_CHAR_TYPE(macro) \
+  macro(char,               char,               ffi_type_uint8) \
+  macro(signed_char,        signed char,        ffi_type_sint8) \
+  macro(unsigned_char,      unsigned char,      ffi_type_uint8)
 
+#define CTYPES_FOR_EACH_CHAR16_TYPE(macro) \
+  macro(char16_t,           char16_t,           ffi_type_uint16)
+
+#define CTYPES_FOR_EACH_TYPE(macro) \
+  CTYPES_FOR_EACH_BOOL_TYPE(macro) \
+  CTYPES_FOR_EACH_INT_TYPE(macro) \
+  CTYPES_FOR_EACH_WRAPPED_INT_TYPE(macro) \
+  CTYPES_FOR_EACH_FLOAT_TYPE(macro) \
+  CTYPES_FOR_EACH_CHAR_TYPE(macro) \
+  CTYPES_FOR_EACH_CHAR16_TYPE(macro)
+
+#endif /* ctypes_typedefs_h */
--- a/toolkit/components/ctypes/tests/jsctypes-test.cpp
+++ b/toolkit/components/ctypes/tests/jsctypes-test.cpp
@@ -2,16 +2,17 @@
 /* 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 "jsctypes-test.h"
 #include <math.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include "typedefs.h"
 
 #if defined(XP_WIN)
 #define snprintf _snprintf
 #endif // defined(XP_WIN)
 
 template <typename T> struct ValueTraits {
   static T literal() { return static_cast<T>(109.25); }
   static T sum(T a, T b) { return a + b; }
@@ -38,78 +39,88 @@ template <> struct ValueTraits<bool> {
 
 void
 test_void_t_cdecl()
 {
   // do nothing
   return;
 }
 
-#define FUNCTION_TESTS(name, type, ffiType, suffix)                            \
+// The "AndUnderscore" bit here is an unfortunate hack: the first argument to
+// DEFINE_CDECL_FUNCTIONS and DEFINE_STDCALL_FUNCTIONS, in addition to being a
+// type, may also be a *macro* on NetBSD -- #define int8_t __int8_t and so on.
+// See <http://mail-index.netbsd.org/tech-toolchain/2014/12/18/msg002479.html>.
+// And unfortunately, passing that macro as an argument to this macro causes it
+// to be expanded -- producing get___int8_t_cdecl() and so on.  Concatenating
+// int8_t with _ slightly muddies this code but inhibits expansion. See also
+// bug 1113379.
+#define FUNCTION_TESTS(nameAndUnderscore, type, ffiType, suffix)               \
 type ABI                                                                       \
-get_##name##_##suffix()                                                        \
+get_##nameAndUnderscore##suffix()                                              \
 {                                                                              \
   return ValueTraits<type>::literal();                                         \
 }                                                                              \
                                                                                \
 type ABI                                                                       \
-set_##name##_##suffix(type x)                                                  \
+set_##nameAndUnderscore##suffix(type x)                                        \
 {                                                                              \
   return x;                                                                    \
 }                                                                              \
                                                                                \
 type ABI                                                                       \
-sum_##name##_##suffix(type x, type y)                                          \
+sum_##nameAndUnderscore##suffix(type x, type y)                                \
 {                                                                              \
   return ValueTraits<type>::sum(x, y);                                         \
 }                                                                              \
                                                                                \
 type ABI                                                                       \
-sum_alignb_##name##_##suffix(char a, type x, char b, type y, char c)           \
+sum_alignb_##nameAndUnderscore##suffix(char a, type x, char b, type y, char c)\
 {                                                                              \
   return ValueTraits<type>::sum(x, y);                                         \
 }                                                                              \
                                                                                \
 type ABI                                                                       \
-sum_alignf_##name##_##suffix(float a, type x, float b, type y, float c)        \
+sum_alignf_##nameAndUnderscore##suffix(float a, type x, float b, type y, float c)\
 {                                                                              \
   return ValueTraits<type>::sum(x, y);                                         \
 }                                                                              \
                                                                                \
 type ABI                                                                       \
-sum_many_##name##_##suffix(                                                    \
+sum_many_##nameAndUnderscore##suffix(                                          \
   type a, type b, type c, type d, type e, type f, type g, type h, type i,      \
   type j, type k, type l, type m, type n, type o, type p, type q, type r)      \
 {                                                                              \
   return ValueTraits<type>::sum_many(a, b, c, d, e, f, g, h, i,                \
                                      j, k, l, m, n, o, p, q, r);               \
 }
 
 #define ABI /* cdecl */
-#define DEFINE_TYPE(x, y, z) FUNCTION_TESTS(x, y, z, cdecl)
-#include "typedefs.h"
+#define DEFINE_CDECL_FUNCTIONS(x, y, z) FUNCTION_TESTS(x##_, y, z, cdecl)
+CTYPES_FOR_EACH_TYPE(DEFINE_CDECL_FUNCTIONS)
+#undef DEFINE_CDECL_FUNCTIONS
 #undef ABI
 
 #if defined(_WIN32)
 
 void NS_STDCALL
 test_void_t_stdcall()
 {
   // do nothing
   return;
 }
 
 #define ABI NS_STDCALL
-#define DEFINE_TYPE(x, y, z) FUNCTION_TESTS(x, y, z, stdcall)
-#include "typedefs.h"
+#define DEFINE_STDCALL_FUNCTIONS(x, y, z) FUNCTION_TESTS(x##_, y, z, stdcall)
+CTYPES_FOR_EACH_TYPE(DEFINE_STDCALL_FUNCTIONS)
+#undef DEFINE_STDCALL_FUNCTIONS
 #undef ABI
 
 #endif /* defined(_WIN32) */
 
-#define DEFINE_TYPE(name, type, ffiType)                                       \
+#define DEFINE_CDECL_TYPE_STATS(name, type, ffiType)                           \
 struct align_##name {                                                          \
   char x;                                                                      \
   type y;                                                                      \
 };                                                                             \
 struct nested_##name {                                                         \
   char a;                                                                      \
   align_##name b;                                                              \
   char c;                                                                      \
@@ -122,17 +133,18 @@ get_##name##_stats(size_t* align, size_t
   *align = offsetof(align_##name, y);                                          \
   *size = sizeof(align_##name);                                                \
   *nalign = offsetof(nested_##name, b);                                        \
   *nsize = sizeof(nested_##name);                                              \
   offsets[0] = offsetof(align_##name, y);                                      \
   offsets[1] = offsetof(nested_##name, b);                                     \
   offsets[2] = offsetof(nested_##name, c);                                     \
 }
-#include "typedefs.h"
+CTYPES_FOR_EACH_TYPE(DEFINE_CDECL_TYPE_STATS)
+#undef DEFINE_CDECL_TYPE_STATS
 
 template <typename T>
 int32_t StrLen(const T* string)
 {
   const T *end;
   for (end = string; *end; ++end);
   return end - string;
 }
--- a/toolkit/components/ctypes/tests/jsctypes-test.h
+++ b/toolkit/components/ctypes/tests/jsctypes-test.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsctypes_test_h
 #define jsctypes_test_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 #include "jspubtd.h"
+#include "typedefs.h"
 
 #define EXPORT_CDECL(type)   MOZ_EXPORT type
 #if defined(_WIN32)
 #if defined(_WIN64)
 #define NS_STDCALL
 #else
 #define NS_STDCALL __stdcall
 #endif
@@ -22,52 +23,52 @@
 
 MOZ_BEGIN_EXTERN_C
 
   EXPORT_CDECL(void) test_void_t_cdecl();
 
   EXPORT_CDECL(void*) get_voidptr_t_cdecl();
   EXPORT_CDECL(void*) set_voidptr_t_cdecl(void*);
 
-#define DEFINE_TYPE(name, type, ffiType)                                       \
+#define DECLARE_CDECL_FUNCTIONS(name, type, ffiType)                           \
   EXPORT_CDECL(type) get_##name##_cdecl();                                     \
   EXPORT_CDECL(type) set_##name##_cdecl(type);                                 \
   EXPORT_CDECL(type) sum_##name##_cdecl(type, type);                           \
   EXPORT_CDECL(type) sum_alignb_##name##_cdecl(char, type, char, type, char);  \
   EXPORT_CDECL(type) sum_alignf_##name##_cdecl(                                \
     float, type, float, type, float);                                          \
   EXPORT_CDECL(type) sum_many_##name##_cdecl(                                  \
     type, type, type, type, type, type, type, type, type,                      \
     type, type, type, type, type, type, type, type, type);                     \
                                                                                \
   EXPORT_CDECL(void) get_##name##_stats(size_t* align, size_t* size,           \
                                         size_t* nalign, size_t* nsize,         \
                                         size_t offsets[]);
-
-#include "typedefs.h"
+  CTYPES_FOR_EACH_TYPE(DECLARE_CDECL_FUNCTIONS)
+#undef DECLARE_CDECL_FUNCTIONS
 
 #if defined(_WIN32)
   EXPORT_STDCALL(void) test_void_t_stdcall();
 
   EXPORT_STDCALL(void*) get_voidptr_t_stdcall();
   EXPORT_STDCALL(void*) set_voidptr_t_stdcall(void*);
 
-#define DEFINE_TYPE(name, type, ffiType)                                       \
+#define DECLARE_STDCALL_FUNCTIONS(name, type, ffiType)                         \
   EXPORT_STDCALL(type) get_##name##_stdcall();                                 \
   EXPORT_STDCALL(type) set_##name##_stdcall(type);                             \
   EXPORT_STDCALL(type) sum_##name##_stdcall(type, type);                       \
   EXPORT_STDCALL(type) sum_alignb_##name##_stdcall(                            \
     char, type, char, type, char);                                             \
   EXPORT_STDCALL(type) sum_alignf_##name##_stdcall(                            \
     float, type, float, type, float);                                          \
   EXPORT_STDCALL(type) sum_many_##name##_stdcall(                              \
     type, type, type, type, type, type, type, type, type,                      \
     type, type, type, type, type, type, type, type, type);
-
-#include "typedefs.h"
+  CTYPES_FOR_EACH_TYPE(DECLARE_STDCALL_FUNCTIONS)
+#undef DECLARE_STDCALL_FUNCTIONS
 
 #endif /* defined(_WIN32) */
 
   MOZ_EXPORT int32_t test_ansi_len(const char*);
   MOZ_EXPORT int32_t test_wide_len(const char16_t*);
   MOZ_EXPORT const char* test_ansi_ret();
   MOZ_EXPORT const char16_t* test_wide_ret();
   MOZ_EXPORT char* test_ansi_echo(const char*);