js/src/ctypes/CTypes.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/ctypes/CTypes.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,7727 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "ctypes/CTypes.h"
    1.11 +
    1.12 +#include "mozilla/FloatingPoint.h"
    1.13 +#include "mozilla/MemoryReporting.h"
    1.14 +#include "mozilla/NumericLimits.h"
    1.15 +
    1.16 +#include <math.h>
    1.17 +#include <stdint.h>
    1.18 +
    1.19 +#if defined(XP_WIN)
    1.20 +#include <float.h>
    1.21 +#endif
    1.22 +
    1.23 +#if defined(SOLARIS)
    1.24 +#include <ieeefp.h>
    1.25 +#endif
    1.26 +
    1.27 +#ifdef HAVE_SSIZE_T
    1.28 +#include <sys/types.h>
    1.29 +#endif
    1.30 +
    1.31 +#if defined(XP_UNIX)
    1.32 +#include <errno.h>
    1.33 +#elif defined(XP_WIN)
    1.34 +#include <windows.h>
    1.35 +#endif
    1.36 +
    1.37 +#include "jscntxt.h"
    1.38 +#include "jsfun.h"
    1.39 +#include "jsnum.h"
    1.40 +#include "jsprf.h"
    1.41 +
    1.42 +#include "builtin/TypedObject.h"
    1.43 +#include "ctypes/Library.h"
    1.44 +
    1.45 +using namespace std;
    1.46 +using mozilla::NumericLimits;
    1.47 +
    1.48 +namespace js {
    1.49 +namespace ctypes {
    1.50 +
    1.51 +size_t
    1.52 +GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
    1.53 +                            size_t nchars)
    1.54 +{
    1.55 +    size_t nbytes;
    1.56 +    const jschar *end;
    1.57 +    unsigned c, c2;
    1.58 +    char buffer[10];
    1.59 +
    1.60 +    nbytes = nchars;
    1.61 +    for (end = chars + nchars; chars != end; chars++) {
    1.62 +        c = *chars;
    1.63 +        if (c < 0x80)
    1.64 +            continue;
    1.65 +        if (0xD800 <= c && c <= 0xDFFF) {
    1.66 +            /* Surrogate pair. */
    1.67 +            chars++;
    1.68 +
    1.69 +            /* nbytes sets 1 length since this is surrogate pair. */
    1.70 +            nbytes--;
    1.71 +            if (c >= 0xDC00 || chars == end)
    1.72 +                goto bad_surrogate;
    1.73 +            c2 = *chars;
    1.74 +            if (c2 < 0xDC00 || c2 > 0xDFFF)
    1.75 +                goto bad_surrogate;
    1.76 +            c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
    1.77 +        }
    1.78 +        c >>= 11;
    1.79 +        nbytes++;
    1.80 +        while (c) {
    1.81 +            c >>= 5;
    1.82 +            nbytes++;
    1.83 +        }
    1.84 +    }
    1.85 +    return nbytes;
    1.86 +
    1.87 +  bad_surrogate:
    1.88 +    if (maybecx) {
    1.89 +        JS_snprintf(buffer, 10, "0x%x", c);
    1.90 +        JS_ReportErrorFlagsAndNumber(maybecx, JSREPORT_ERROR, js_GetErrorMessage,
    1.91 +                                     nullptr, JSMSG_BAD_SURROGATE_CHAR, buffer);
    1.92 +    }
    1.93 +    return (size_t) -1;
    1.94 +}
    1.95 +
    1.96 +bool
    1.97 +DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
    1.98 +                              char *dst, size_t *dstlenp)
    1.99 +{
   1.100 +    size_t i, utf8Len;
   1.101 +    jschar c, c2;
   1.102 +    uint32_t v;
   1.103 +    uint8_t utf8buf[6];
   1.104 +
   1.105 +    size_t dstlen = *dstlenp;
   1.106 +    size_t origDstlen = dstlen;
   1.107 +
   1.108 +    while (srclen) {
   1.109 +        c = *src++;
   1.110 +        srclen--;
   1.111 +        if (c >= 0xDC00 && c <= 0xDFFF)
   1.112 +            goto badSurrogate;
   1.113 +        if (c < 0xD800 || c > 0xDBFF) {
   1.114 +            v = c;
   1.115 +        } else {
   1.116 +            if (srclen < 1)
   1.117 +                goto badSurrogate;
   1.118 +            c2 = *src;
   1.119 +            if ((c2 < 0xDC00) || (c2 > 0xDFFF))
   1.120 +                goto badSurrogate;
   1.121 +            src++;
   1.122 +            srclen--;
   1.123 +            v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
   1.124 +        }
   1.125 +        if (v < 0x0080) {
   1.126 +            /* no encoding necessary - performance hack */
   1.127 +            if (dstlen == 0)
   1.128 +                goto bufferTooSmall;
   1.129 +            *dst++ = (char) v;
   1.130 +            utf8Len = 1;
   1.131 +        } else {
   1.132 +            utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
   1.133 +            if (utf8Len > dstlen)
   1.134 +                goto bufferTooSmall;
   1.135 +            for (i = 0; i < utf8Len; i++)
   1.136 +                *dst++ = (char) utf8buf[i];
   1.137 +        }
   1.138 +        dstlen -= utf8Len;
   1.139 +    }
   1.140 +    *dstlenp = (origDstlen - dstlen);
   1.141 +    return true;
   1.142 +
   1.143 +badSurrogate:
   1.144 +    *dstlenp = (origDstlen - dstlen);
   1.145 +    /* Delegate error reporting to the measurement function. */
   1.146 +    if (maybecx)
   1.147 +        GetDeflatedUTF8StringLength(maybecx, src - 1, srclen + 1);
   1.148 +    return false;
   1.149 +
   1.150 +bufferTooSmall:
   1.151 +    *dstlenp = (origDstlen - dstlen);
   1.152 +    if (maybecx) {
   1.153 +        JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr,
   1.154 +                             JSMSG_BUFFER_TOO_SMALL);
   1.155 +    }
   1.156 +    return false;
   1.157 +}
   1.158 +
   1.159 +/*******************************************************************************
   1.160 +** JSAPI function prototypes
   1.161 +*******************************************************************************/
   1.162 +
   1.163 +// We use an enclosing struct here out of paranoia about the ability of gcc 4.4
   1.164 +// (and maybe 4.5) to correctly compile this if it were a template function.
   1.165 +// See also the comments in dom/workers/Events.cpp (and other adjacent files) by
   1.166 +// the |struct Property| there.
   1.167 +template<JS::IsAcceptableThis Test, JS::NativeImpl Impl>
   1.168 +struct Property
   1.169 +{
   1.170 +  static bool
   1.171 +  Fun(JSContext* cx, unsigned argc, JS::Value* vp)
   1.172 +  {
   1.173 +    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   1.174 +    return JS::CallNonGenericMethod<Test, Impl>(cx, args);
   1.175 +  }
   1.176 +};
   1.177 +
   1.178 +static bool ConstructAbstract(JSContext* cx, unsigned argc, jsval* vp);
   1.179 +
   1.180 +namespace CType {
   1.181 +  static bool ConstructData(JSContext* cx, unsigned argc, jsval* vp);
   1.182 +  static bool ConstructBasic(JSContext* cx, HandleObject obj, const CallArgs& args);
   1.183 +
   1.184 +  static void Trace(JSTracer* trc, JSObject* obj);
   1.185 +  static void Finalize(JSFreeOp *fop, JSObject* obj);
   1.186 +
   1.187 +  bool IsCType(HandleValue v);
   1.188 +  bool IsCTypeOrProto(HandleValue v);
   1.189 +
   1.190 +  bool PrototypeGetter(JSContext* cx, JS::CallArgs args);
   1.191 +  bool NameGetter(JSContext* cx, JS::CallArgs args);
   1.192 +  bool SizeGetter(JSContext* cx, JS::CallArgs args);
   1.193 +  bool PtrGetter(JSContext* cx, JS::CallArgs args);
   1.194 +
   1.195 +  static bool CreateArray(JSContext* cx, unsigned argc, jsval* vp);
   1.196 +  static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   1.197 +  static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   1.198 +  static bool HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp);
   1.199 +
   1.200 +
   1.201 +  /*
   1.202 +   * Get the global "ctypes" object.
   1.203 +   *
   1.204 +   * |obj| must be a CType object.
   1.205 +   *
   1.206 +   * This function never returns nullptr.
   1.207 +   */
   1.208 +  static JSObject* GetGlobalCTypes(JSContext* cx, JSObject* obj);
   1.209 +
   1.210 +}
   1.211 +
   1.212 +namespace ABI {
   1.213 +  bool IsABI(JSObject* obj);
   1.214 +  static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   1.215 +}
   1.216 +
   1.217 +namespace PointerType {
   1.218 +  static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   1.219 +  static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   1.220 +
   1.221 +  bool IsPointerType(HandleValue v);
   1.222 +  bool IsPointer(HandleValue v);
   1.223 +
   1.224 +  bool TargetTypeGetter(JSContext* cx, JS::CallArgs args);
   1.225 +  bool ContentsGetter(JSContext* cx, JS::CallArgs args);
   1.226 +  bool ContentsSetter(JSContext* cx, JS::CallArgs args);
   1.227 +
   1.228 +  static bool IsNull(JSContext* cx, unsigned argc, jsval* vp);
   1.229 +  static bool Increment(JSContext* cx, unsigned argc, jsval* vp);
   1.230 +  static bool Decrement(JSContext* cx, unsigned argc, jsval* vp);
   1.231 +  // The following is not an instance function, since we don't want to expose arbitrary
   1.232 +  // pointer arithmetic at this moment.
   1.233 +  static bool OffsetBy(JSContext* cx, const CallArgs& args, int offset);
   1.234 +}
   1.235 +
   1.236 +namespace ArrayType {
   1.237 +  bool IsArrayType(HandleValue v);
   1.238 +  bool IsArrayOrArrayType(HandleValue v);
   1.239 +
   1.240 +  static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   1.241 +  static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   1.242 +
   1.243 +  bool ElementTypeGetter(JSContext* cx, JS::CallArgs args);
   1.244 +  bool LengthGetter(JSContext* cx, JS::CallArgs args);
   1.245 +
   1.246 +  static bool Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp);
   1.247 +  static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp);
   1.248 +  static bool AddressOfElement(JSContext* cx, unsigned argc, jsval* vp);
   1.249 +}
   1.250 +
   1.251 +namespace StructType {
   1.252 +  bool IsStruct(HandleValue v);
   1.253 +
   1.254 +  static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   1.255 +  static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   1.256 +
   1.257 +  bool FieldsArrayGetter(JSContext* cx, JS::CallArgs args);
   1.258 +
   1.259 +  static bool FieldGetter(JSContext* cx, HandleObject obj, HandleId idval,
   1.260 +    MutableHandleValue vp);
   1.261 +  static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
   1.262 +                            MutableHandleValue vp);
   1.263 +  static bool AddressOfField(JSContext* cx, unsigned argc, jsval* vp);
   1.264 +  static bool Define(JSContext* cx, unsigned argc, jsval* vp);
   1.265 +}
   1.266 +
   1.267 +namespace FunctionType {
   1.268 +  static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   1.269 +  static bool ConstructData(JSContext* cx, HandleObject typeObj,
   1.270 +    HandleObject dataObj, HandleObject fnObj, HandleObject thisObj, jsval errVal);
   1.271 +
   1.272 +  static bool Call(JSContext* cx, unsigned argc, jsval* vp);
   1.273 +
   1.274 +  bool IsFunctionType(HandleValue v);
   1.275 +
   1.276 +  bool ArgTypesGetter(JSContext* cx, JS::CallArgs args);
   1.277 +  bool ReturnTypeGetter(JSContext* cx, JS::CallArgs args);
   1.278 +  bool ABIGetter(JSContext* cx, JS::CallArgs args);
   1.279 +  bool IsVariadicGetter(JSContext* cx, JS::CallArgs args);
   1.280 +}
   1.281 +
   1.282 +namespace CClosure {
   1.283 +  static void Trace(JSTracer* trc, JSObject* obj);
   1.284 +  static void Finalize(JSFreeOp *fop, JSObject* obj);
   1.285 +
   1.286 +  // libffi callback
   1.287 +  static void ClosureStub(ffi_cif* cif, void* result, void** args,
   1.288 +    void* userData);
   1.289 +}
   1.290 +
   1.291 +namespace CData {
   1.292 +  static void Finalize(JSFreeOp *fop, JSObject* obj);
   1.293 +
   1.294 +  bool ValueGetter(JSContext* cx, JS::CallArgs args);
   1.295 +  bool ValueSetter(JSContext* cx, JS::CallArgs args);
   1.296 +
   1.297 +  static bool Address(JSContext* cx, unsigned argc, jsval* vp);
   1.298 +  static bool ReadString(JSContext* cx, unsigned argc, jsval* vp);
   1.299 +  static bool ReadStringReplaceMalformed(JSContext* cx, unsigned argc, jsval* vp);
   1.300 +  static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   1.301 +  static JSString *GetSourceString(JSContext *cx, HandleObject typeObj,
   1.302 +                                   void *data);
   1.303 +
   1.304 +  bool ErrnoGetter(JSContext* cx, JS::CallArgs args);
   1.305 +
   1.306 +#if defined(XP_WIN)
   1.307 +  bool LastErrorGetter(JSContext* cx, JS::CallArgs args);
   1.308 +#endif // defined(XP_WIN)
   1.309 +}
   1.310 +
   1.311 +namespace CDataFinalizer {
   1.312 +  /*
   1.313 +   * Attach a C function as a finalizer to a JS object.
   1.314 +   *
   1.315 +   * This function is available from JS as |ctypes.withFinalizer|.
   1.316 +   *
   1.317 +   * JavaScript signature:
   1.318 +   * function(CData, CData):   CDataFinalizer
   1.319 +   *          value  finalizer finalizable
   1.320 +   *
   1.321 +   * Where |finalizer| is a one-argument function taking a value
   1.322 +   * with the same type as |value|.
   1.323 +   */
   1.324 +  static bool Construct(JSContext* cx, unsigned argc, jsval *vp);
   1.325 +
   1.326 +  /*
   1.327 +   * Private data held by |CDataFinalizer|.
   1.328 +   *
   1.329 +   * See also |enum CDataFinalizerSlot| for the slots of
   1.330 +   * |CDataFinalizer|.
   1.331 +   *
   1.332 +   * Note: the private data may be nullptr, if |dispose|, |forget| or the
   1.333 +   * finalizer has already been called.
   1.334 +   */
   1.335 +  struct Private {
   1.336 +    /*
   1.337 +     * The C data to pass to the code.
   1.338 +     * Finalization/|dispose|/|forget| release this memory.
   1.339 +     */
   1.340 +    void *cargs;
   1.341 +
   1.342 +    /*
   1.343 +     * The total size of the buffer pointed by |cargs|
   1.344 +     */
   1.345 +    size_t cargs_size;
   1.346 +
   1.347 +    /*
   1.348 +     * Low-level signature information.
   1.349 +     * Finalization/|dispose|/|forget| release this memory.
   1.350 +     */
   1.351 +    ffi_cif CIF;
   1.352 +
   1.353 +    /*
   1.354 +     * The C function to invoke during finalization.
   1.355 +     * Do not deallocate this.
   1.356 +     */
   1.357 +    uintptr_t code;
   1.358 +
   1.359 +    /*
   1.360 +     * A buffer for holding the return value.
   1.361 +     * Finalization/|dispose|/|forget| release this memory.
   1.362 +     */
   1.363 +    void *rvalue;
   1.364 +  };
   1.365 +
   1.366 +  /*
   1.367 +   * Methods of instances of |CDataFinalizer|
   1.368 +   */
   1.369 +  namespace Methods {
   1.370 +    static bool Dispose(JSContext* cx, unsigned argc, jsval *vp);
   1.371 +    static bool Forget(JSContext* cx, unsigned argc, jsval *vp);
   1.372 +    static bool ToSource(JSContext* cx, unsigned argc, jsval *vp);
   1.373 +    static bool ToString(JSContext* cx, unsigned argc, jsval *vp);
   1.374 +  }
   1.375 +
   1.376 +  /*
   1.377 +   * Utility functions
   1.378 +   *
   1.379 +   * @return true if |obj| is a CDataFinalizer, false otherwise.
   1.380 +   */
   1.381 +  static bool IsCDataFinalizer(JSObject *obj);
   1.382 +
   1.383 +  /*
   1.384 +   * Clean up the finalization information of a CDataFinalizer.
   1.385 +   *
   1.386 +   * Used by |Finalize|, |Dispose| and |Forget|.
   1.387 +   *
   1.388 +   * @param p The private information of the CDataFinalizer. If nullptr,
   1.389 +   * this function does nothing.
   1.390 +   * @param obj Either nullptr, if the object should not be cleaned up (i.e.
   1.391 +   * during finalization) or a CDataFinalizer JSObject. Always use nullptr
   1.392 +   * if you are calling from a finalizer.
   1.393 +   */
   1.394 +  static void Cleanup(Private *p, JSObject *obj);
   1.395 +
   1.396 +  /*
   1.397 +   * Perform the actual call to the finalizer code.
   1.398 +   */
   1.399 +  static void CallFinalizer(CDataFinalizer::Private *p,
   1.400 +                            int* errnoStatus,
   1.401 +                            int32_t* lastErrorStatus);
   1.402 +
   1.403 +  /*
   1.404 +   * Return the CType of a CDataFinalizer object, or nullptr if the object
   1.405 +   * has been cleaned-up already.
   1.406 +   */
   1.407 +  static JSObject *GetCType(JSContext *cx, JSObject *obj);
   1.408 +
   1.409 +  /*
   1.410 +   * Perform finalization of a |CDataFinalizer|
   1.411 +   */
   1.412 +  static void Finalize(JSFreeOp *fop, JSObject *obj);
   1.413 +
   1.414 +  /*
   1.415 +   * Return the jsval contained by this finalizer.
   1.416 +   *
   1.417 +   * Note that the jsval is actually not recorded, but converted back from C.
   1.418 +   */
   1.419 +  static bool GetValue(JSContext *cx, JSObject *obj, jsval *result);
   1.420 +
   1.421 +  static JSObject* GetCData(JSContext *cx, JSObject *obj);
   1.422 + }
   1.423 +
   1.424 +
   1.425 +// Int64Base provides functions common to Int64 and UInt64.
   1.426 +namespace Int64Base {
   1.427 +  JSObject* Construct(JSContext* cx, HandleObject proto, uint64_t data,
   1.428 +    bool isUnsigned);
   1.429 +
   1.430 +  uint64_t GetInt(JSObject* obj);
   1.431 +
   1.432 +  bool ToString(JSContext* cx, JSObject* obj, const CallArgs& args,
   1.433 +                bool isUnsigned);
   1.434 +
   1.435 +  bool ToSource(JSContext* cx, JSObject* obj, const CallArgs& args,
   1.436 +                bool isUnsigned);
   1.437 +
   1.438 +  static void Finalize(JSFreeOp *fop, JSObject* obj);
   1.439 +}
   1.440 +
   1.441 +namespace Int64 {
   1.442 +  static bool Construct(JSContext* cx, unsigned argc, jsval* vp);
   1.443 +
   1.444 +  static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   1.445 +  static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   1.446 +
   1.447 +  static bool Compare(JSContext* cx, unsigned argc, jsval* vp);
   1.448 +  static bool Lo(JSContext* cx, unsigned argc, jsval* vp);
   1.449 +  static bool Hi(JSContext* cx, unsigned argc, jsval* vp);
   1.450 +  static bool Join(JSContext* cx, unsigned argc, jsval* vp);
   1.451 +}
   1.452 +
   1.453 +namespace UInt64 {
   1.454 +  static bool Construct(JSContext* cx, unsigned argc, jsval* vp);
   1.455 +
   1.456 +  static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   1.457 +  static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   1.458 +
   1.459 +  static bool Compare(JSContext* cx, unsigned argc, jsval* vp);
   1.460 +  static bool Lo(JSContext* cx, unsigned argc, jsval* vp);
   1.461 +  static bool Hi(JSContext* cx, unsigned argc, jsval* vp);
   1.462 +  static bool Join(JSContext* cx, unsigned argc, jsval* vp);
   1.463 +}
   1.464 +
   1.465 +/*******************************************************************************
   1.466 +** JSClass definitions and initialization functions
   1.467 +*******************************************************************************/
   1.468 +
   1.469 +// Class representing the 'ctypes' object itself. This exists to contain the
   1.470 +// JSCTypesCallbacks set of function pointers.
   1.471 +static const JSClass sCTypesGlobalClass = {
   1.472 +  "ctypes",
   1.473 +  JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS),
   1.474 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.475 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.476 +};
   1.477 +
   1.478 +static const JSClass sCABIClass = {
   1.479 +  "CABI",
   1.480 +  JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS),
   1.481 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.482 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.483 +};
   1.484 +
   1.485 +// Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype.
   1.486 +// This exists to give said prototypes a class of "CType", and to provide
   1.487 +// reserved slots for stashing various other prototype objects.
   1.488 +static const JSClass sCTypeProtoClass = {
   1.489 +  "CType",
   1.490 +  JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
   1.491 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.492 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
   1.493 +  ConstructAbstract, nullptr, ConstructAbstract
   1.494 +};
   1.495 +
   1.496 +// Class representing ctypes.CData.prototype and the 'prototype' properties
   1.497 +// of CTypes. This exists to give said prototypes a class of "CData".
   1.498 +static const JSClass sCDataProtoClass = {
   1.499 +  "CData",
   1.500 +  0,
   1.501 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.502 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.503 +};
   1.504 +
   1.505 +static const JSClass sCTypeClass = {
   1.506 +  "CType",
   1.507 +  JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
   1.508 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.509 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize,
   1.510 +  CType::ConstructData, CType::HasInstance, CType::ConstructData,
   1.511 +  CType::Trace
   1.512 +};
   1.513 +
   1.514 +static const JSClass sCDataClass = {
   1.515 +  "CData",
   1.516 +  JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
   1.517 +  JS_PropertyStub, JS_DeletePropertyStub, ArrayType::Getter, ArrayType::Setter,
   1.518 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize,
   1.519 +  FunctionType::Call, nullptr, FunctionType::Call
   1.520 +};
   1.521 +
   1.522 +static const JSClass sCClosureClass = {
   1.523 +  "CClosure",
   1.524 +  JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
   1.525 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.526 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize,
   1.527 +  nullptr, nullptr, nullptr, CClosure::Trace
   1.528 +};
   1.529 +
   1.530 +/*
   1.531 + * Class representing the prototype of CDataFinalizer.
   1.532 + */
   1.533 +static const JSClass sCDataFinalizerProtoClass = {
   1.534 +  "CDataFinalizer",
   1.535 +  0,
   1.536 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.537 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.538 +};
   1.539 +
   1.540 +/*
   1.541 + * Class representing instances of CDataFinalizer.
   1.542 + *
   1.543 + * Instances of CDataFinalizer have both private data (with type
   1.544 + * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|).
   1.545 + */
   1.546 +static const JSClass sCDataFinalizerClass = {
   1.547 +  "CDataFinalizer",
   1.548 +  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS),
   1.549 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.550 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CDataFinalizer::Finalize,
   1.551 +};
   1.552 +
   1.553 +
   1.554 +#define CTYPESFN_FLAGS \
   1.555 +  (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
   1.556 +
   1.557 +#define CTYPESCTOR_FLAGS \
   1.558 +  (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR)
   1.559 +
   1.560 +#define CTYPESACC_FLAGS \
   1.561 +  (JSPROP_ENUMERATE | JSPROP_PERMANENT)
   1.562 +
   1.563 +#define CABIFN_FLAGS \
   1.564 +  (JSPROP_READONLY | JSPROP_PERMANENT)
   1.565 +
   1.566 +#define CDATAFN_FLAGS \
   1.567 +  (JSPROP_READONLY | JSPROP_PERMANENT)
   1.568 +
   1.569 +#define CDATAFINALIZERFN_FLAGS \
   1.570 +  (JSPROP_READONLY | JSPROP_PERMANENT)
   1.571 +
   1.572 +static const JSPropertySpec sCTypeProps[] = {
   1.573 +  JS_PSG("name",
   1.574 +         (Property<CType::IsCType, CType::NameGetter>::Fun),
   1.575 +         CTYPESACC_FLAGS),
   1.576 +  JS_PSG("size",
   1.577 +         (Property<CType::IsCType, CType::SizeGetter>::Fun),
   1.578 +         CTYPESACC_FLAGS),
   1.579 +  JS_PSG("ptr",
   1.580 +         (Property<CType::IsCType, CType::PtrGetter>::Fun),
   1.581 +         CTYPESACC_FLAGS),
   1.582 +  JS_PSG("prototype",
   1.583 +         (Property<CType::IsCTypeOrProto, CType::PrototypeGetter>::Fun),
   1.584 +         CTYPESACC_FLAGS),
   1.585 +  JS_PS_END
   1.586 +};
   1.587 +
   1.588 +static const JSFunctionSpec sCTypeFunctions[] = {
   1.589 +  JS_FN("array", CType::CreateArray, 0, CTYPESFN_FLAGS),
   1.590 +  JS_FN("toString", CType::ToString, 0, CTYPESFN_FLAGS),
   1.591 +  JS_FN("toSource", CType::ToSource, 0, CTYPESFN_FLAGS),
   1.592 +  JS_FS_END
   1.593 +};
   1.594 +
   1.595 +static const JSFunctionSpec sCABIFunctions[] = {
   1.596 +  JS_FN("toSource", ABI::ToSource, 0, CABIFN_FLAGS),
   1.597 +  JS_FN("toString", ABI::ToSource, 0, CABIFN_FLAGS),
   1.598 +  JS_FS_END
   1.599 +};
   1.600 +
   1.601 +static const JSPropertySpec sCDataProps[] = {
   1.602 +  JS_PSGS("value",
   1.603 +          (Property<CData::IsCData, CData::ValueGetter>::Fun),
   1.604 +          (Property<CData::IsCData, CData::ValueSetter>::Fun),
   1.605 +          JSPROP_PERMANENT),
   1.606 +  JS_PS_END
   1.607 +};
   1.608 +
   1.609 +static const JSFunctionSpec sCDataFunctions[] = {
   1.610 +  JS_FN("address", CData::Address, 0, CDATAFN_FLAGS),
   1.611 +  JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS),
   1.612 +  JS_FN("readStringReplaceMalformed", CData::ReadStringReplaceMalformed, 0, CDATAFN_FLAGS),
   1.613 +  JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS),
   1.614 +  JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS),
   1.615 +  JS_FS_END
   1.616 +};
   1.617 +
   1.618 +static const JSFunctionSpec sCDataFinalizerFunctions[] = {
   1.619 +  JS_FN("dispose",  CDataFinalizer::Methods::Dispose,  0, CDATAFINALIZERFN_FLAGS),
   1.620 +  JS_FN("forget",   CDataFinalizer::Methods::Forget,   0, CDATAFINALIZERFN_FLAGS),
   1.621 +  JS_FN("readString",CData::ReadString, 0, CDATAFINALIZERFN_FLAGS),
   1.622 +  JS_FN("toString", CDataFinalizer::Methods::ToString, 0, CDATAFINALIZERFN_FLAGS),
   1.623 +  JS_FN("toSource", CDataFinalizer::Methods::ToSource, 0, CDATAFINALIZERFN_FLAGS),
   1.624 +  JS_FS_END
   1.625 +};
   1.626 +
   1.627 +static const JSFunctionSpec sPointerFunction =
   1.628 +  JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS);
   1.629 +
   1.630 +static const JSPropertySpec sPointerProps[] = {
   1.631 +  JS_PSG("targetType",
   1.632 +         (Property<PointerType::IsPointerType, PointerType::TargetTypeGetter>::Fun),
   1.633 +         CTYPESACC_FLAGS),
   1.634 +  JS_PS_END
   1.635 +};
   1.636 +
   1.637 +static const JSFunctionSpec sPointerInstanceFunctions[] = {
   1.638 +  JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS),
   1.639 +  JS_FN("increment", PointerType::Increment, 0, CTYPESFN_FLAGS),
   1.640 +  JS_FN("decrement", PointerType::Decrement, 0, CTYPESFN_FLAGS),
   1.641 +  JS_FS_END
   1.642 +};
   1.643 +
   1.644 +static const JSPropertySpec sPointerInstanceProps[] = {
   1.645 +  JS_PSGS("contents",
   1.646 +         (Property<PointerType::IsPointer, PointerType::ContentsGetter>::Fun),
   1.647 +         (Property<PointerType::IsPointer, PointerType::ContentsSetter>::Fun),
   1.648 +          JSPROP_PERMANENT),
   1.649 +  JS_PS_END
   1.650 +};
   1.651 +
   1.652 +static const JSFunctionSpec sArrayFunction =
   1.653 +  JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS);
   1.654 +
   1.655 +static const JSPropertySpec sArrayProps[] = {
   1.656 +  JS_PSG("elementType",
   1.657 +         (Property<ArrayType::IsArrayType, ArrayType::ElementTypeGetter>::Fun),
   1.658 +         CTYPESACC_FLAGS),
   1.659 +  JS_PSG("length",
   1.660 +         (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
   1.661 +         CTYPESACC_FLAGS),
   1.662 +  JS_PS_END
   1.663 +};
   1.664 +
   1.665 +static const JSFunctionSpec sArrayInstanceFunctions[] = {
   1.666 +  JS_FN("addressOfElement", ArrayType::AddressOfElement, 1, CDATAFN_FLAGS),
   1.667 +  JS_FS_END
   1.668 +};
   1.669 +
   1.670 +static const JSPropertySpec sArrayInstanceProps[] = {
   1.671 +  JS_PSG("length",
   1.672 +         (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
   1.673 +         JSPROP_PERMANENT),
   1.674 +  JS_PS_END
   1.675 +};
   1.676 +
   1.677 +static const JSFunctionSpec sStructFunction =
   1.678 +  JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS);
   1.679 +
   1.680 +static const JSPropertySpec sStructProps[] = {
   1.681 +  JS_PSG("fields",
   1.682 +         (Property<StructType::IsStruct, StructType::FieldsArrayGetter>::Fun),
   1.683 +         CTYPESACC_FLAGS),
   1.684 +  JS_PS_END
   1.685 +};
   1.686 +
   1.687 +static const JSFunctionSpec sStructFunctions[] = {
   1.688 +  JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS),
   1.689 +  JS_FS_END
   1.690 +};
   1.691 +
   1.692 +static const JSFunctionSpec sStructInstanceFunctions[] = {
   1.693 +  JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS),
   1.694 +  JS_FS_END
   1.695 +};
   1.696 +
   1.697 +static const JSFunctionSpec sFunctionFunction =
   1.698 +  JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS);
   1.699 +
   1.700 +static const JSPropertySpec sFunctionProps[] = {
   1.701 +  JS_PSG("argTypes",
   1.702 +         (Property<FunctionType::IsFunctionType, FunctionType::ArgTypesGetter>::Fun),
   1.703 +         CTYPESACC_FLAGS),
   1.704 +  JS_PSG("returnType",
   1.705 +         (Property<FunctionType::IsFunctionType, FunctionType::ReturnTypeGetter>::Fun),
   1.706 +         CTYPESACC_FLAGS),
   1.707 +  JS_PSG("abi",
   1.708 +         (Property<FunctionType::IsFunctionType, FunctionType::ABIGetter>::Fun),
   1.709 +         CTYPESACC_FLAGS),
   1.710 +  JS_PSG("isVariadic",
   1.711 +         (Property<FunctionType::IsFunctionType, FunctionType::IsVariadicGetter>::Fun),
   1.712 +         CTYPESACC_FLAGS),
   1.713 +  JS_PS_END
   1.714 +};
   1.715 +
   1.716 +static const JSFunctionSpec sFunctionInstanceFunctions[] = {
   1.717 +  JS_FN("call", js_fun_call, 1, CDATAFN_FLAGS),
   1.718 +  JS_FN("apply", js_fun_apply, 2, CDATAFN_FLAGS),
   1.719 +  JS_FS_END
   1.720 +};
   1.721 +
   1.722 +static const JSClass sInt64ProtoClass = {
   1.723 +  "Int64",
   1.724 +  0,
   1.725 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.726 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.727 +};
   1.728 +
   1.729 +static const JSClass sUInt64ProtoClass = {
   1.730 +  "UInt64",
   1.731 +  0,
   1.732 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.733 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   1.734 +};
   1.735 +
   1.736 +static const JSClass sInt64Class = {
   1.737 +  "Int64",
   1.738 +  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
   1.739 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.740 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
   1.741 +};
   1.742 +
   1.743 +static const JSClass sUInt64Class = {
   1.744 +  "UInt64",
   1.745 +  JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
   1.746 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.747 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
   1.748 +};
   1.749 +
   1.750 +static const JSFunctionSpec sInt64StaticFunctions[] = {
   1.751 +  JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS),
   1.752 +  JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS),
   1.753 +  JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS),
   1.754 +  JS_FN("join", Int64::Join, 2, CTYPESFN_FLAGS),
   1.755 +  JS_FS_END
   1.756 +};
   1.757 +
   1.758 +static const JSFunctionSpec sUInt64StaticFunctions[] = {
   1.759 +  JS_FN("compare", UInt64::Compare, 2, CTYPESFN_FLAGS),
   1.760 +  JS_FN("lo", UInt64::Lo, 1, CTYPESFN_FLAGS),
   1.761 +  JS_FN("hi", UInt64::Hi, 1, CTYPESFN_FLAGS),
   1.762 +  JS_FN("join", UInt64::Join, 2, CTYPESFN_FLAGS),
   1.763 +  JS_FS_END
   1.764 +};
   1.765 +
   1.766 +static const JSFunctionSpec sInt64Functions[] = {
   1.767 +  JS_FN("toString", Int64::ToString, 0, CTYPESFN_FLAGS),
   1.768 +  JS_FN("toSource", Int64::ToSource, 0, CTYPESFN_FLAGS),
   1.769 +  JS_FS_END
   1.770 +};
   1.771 +
   1.772 +static const JSFunctionSpec sUInt64Functions[] = {
   1.773 +  JS_FN("toString", UInt64::ToString, 0, CTYPESFN_FLAGS),
   1.774 +  JS_FN("toSource", UInt64::ToSource, 0, CTYPESFN_FLAGS),
   1.775 +  JS_FS_END
   1.776 +};
   1.777 +
   1.778 +static const JSPropertySpec sModuleProps[] = {
   1.779 +  JS_PSG("errno",
   1.780 +         (Property<IsCTypesGlobal, CData::ErrnoGetter>::Fun),
   1.781 +         JSPROP_PERMANENT),
   1.782 +#if defined(XP_WIN)
   1.783 +  JS_PSG("winLastError",
   1.784 +         (Property<IsCTypesGlobal, CData::LastErrorGetter>::Fun),
   1.785 +         JSPROP_PERMANENT),
   1.786 +#endif // defined(XP_WIN)
   1.787 +  JS_PS_END
   1.788 +};
   1.789 +
   1.790 +static const JSFunctionSpec sModuleFunctions[] = {
   1.791 +  JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS),
   1.792 +  JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
   1.793 +  JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
   1.794 +  JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
   1.795 +  JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
   1.796 +  JS_FS_END
   1.797 +};
   1.798 +
   1.799 +static MOZ_ALWAYS_INLINE JSString*
   1.800 +NewUCString(JSContext* cx, const AutoString& from)
   1.801 +{
   1.802 +  return JS_NewUCStringCopyN(cx, from.begin(), from.length());
   1.803 +}
   1.804 +
   1.805 +/*
   1.806 + * Return a size rounded up to a multiple of a power of two.
   1.807 + *
   1.808 + * Note: |align| must be a power of 2.
   1.809 + */
   1.810 +static MOZ_ALWAYS_INLINE size_t
   1.811 +Align(size_t val, size_t align)
   1.812 +{
   1.813 +  // Ensure that align is a power of two.
   1.814 +  MOZ_ASSERT(align != 0 && (align & (align - 1)) == 0);
   1.815 +  return ((val - 1) | (align - 1)) + 1;
   1.816 +}
   1.817 +
   1.818 +static ABICode
   1.819 +GetABICode(JSObject* obj)
   1.820 +{
   1.821 +  // make sure we have an object representing a CABI class,
   1.822 +  // and extract the enumerated class type from the reserved slot.
   1.823 +  if (JS_GetClass(obj) != &sCABIClass)
   1.824 +    return INVALID_ABI;
   1.825 +
   1.826 +  jsval result = JS_GetReservedSlot(obj, SLOT_ABICODE);
   1.827 +  return ABICode(JSVAL_TO_INT(result));
   1.828 +}
   1.829 +
   1.830 +static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
   1.831 +#define MSG_DEF(name, number, count, exception, format) \
   1.832 +  { format, count, exception } ,
   1.833 +#include "ctypes/ctypes.msg"
   1.834 +#undef MSG_DEF
   1.835 +};
   1.836 +
   1.837 +static const JSErrorFormatString*
   1.838 +GetErrorMessage(void* userRef, const char* locale, const unsigned errorNumber)
   1.839 +{
   1.840 +  if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
   1.841 +    return &ErrorFormatString[errorNumber];
   1.842 +  return nullptr;
   1.843 +}
   1.844 +
   1.845 +static bool
   1.846 +TypeError(JSContext* cx, const char* expected, HandleValue actual)
   1.847 +{
   1.848 +  JSString* str = JS_ValueToSource(cx, actual);
   1.849 +  JSAutoByteString bytes;
   1.850 +
   1.851 +  const char* src;
   1.852 +  if (str) {
   1.853 +    src = bytes.encodeLatin1(cx, str);
   1.854 +    if (!src)
   1.855 +      return false;
   1.856 +  } else {
   1.857 +    JS_ClearPendingException(cx);
   1.858 +    src = "<<error converting value to string>>";
   1.859 +  }
   1.860 +  JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
   1.861 +                       CTYPESMSG_TYPE_ERROR, expected, src);
   1.862 +  return false;
   1.863 +}
   1.864 +
   1.865 +static JSObject*
   1.866 +InitCTypeClass(JSContext* cx, HandleObject parent)
   1.867 +{
   1.868 +  JSFunction *fun = JS_DefineFunction(cx, parent, "CType", ConstructAbstract, 0,
   1.869 +                                      CTYPESCTOR_FLAGS);
   1.870 +  if (!fun)
   1.871 +    return nullptr;
   1.872 +
   1.873 +  RootedObject ctor(cx, JS_GetFunctionObject(fun));
   1.874 +  RootedObject fnproto(cx);
   1.875 +  if (!JS_GetPrototype(cx, ctor, &fnproto))
   1.876 +    return nullptr;
   1.877 +  JS_ASSERT(ctor);
   1.878 +  JS_ASSERT(fnproto);
   1.879 +
   1.880 +  // Set up ctypes.CType.prototype.
   1.881 +  RootedObject prototype(cx, JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent));
   1.882 +  if (!prototype)
   1.883 +    return nullptr;
   1.884 +
   1.885 +  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
   1.886 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   1.887 +    return nullptr;
   1.888 +
   1.889 +  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
   1.890 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   1.891 +    return nullptr;
   1.892 +
   1.893 +  // Define properties and functions common to all CTypes.
   1.894 +  if (!JS_DefineProperties(cx, prototype, sCTypeProps) ||
   1.895 +      !JS_DefineFunctions(cx, prototype, sCTypeFunctions))
   1.896 +    return nullptr;
   1.897 +
   1.898 +  if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
   1.899 +    return nullptr;
   1.900 +
   1.901 +  return prototype;
   1.902 +}
   1.903 +
   1.904 +static JSObject*
   1.905 +InitABIClass(JSContext* cx, JSObject* parent)
   1.906 +{
   1.907 +  RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
   1.908 +
   1.909 +  if (!obj)
   1.910 +    return nullptr;
   1.911 +
   1.912 +  if (!JS_DefineFunctions(cx, obj, sCABIFunctions))
   1.913 +    return nullptr;
   1.914 +
   1.915 +  return obj;
   1.916 +}
   1.917 +
   1.918 +
   1.919 +static JSObject*
   1.920 +InitCDataClass(JSContext* cx, HandleObject parent, HandleObject CTypeProto)
   1.921 +{
   1.922 +  JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0,
   1.923 +                      CTYPESCTOR_FLAGS);
   1.924 +  if (!fun)
   1.925 +    return nullptr;
   1.926 +
   1.927 +  RootedObject ctor(cx, JS_GetFunctionObject(fun));
   1.928 +  JS_ASSERT(ctor);
   1.929 +
   1.930 +  // Set up ctypes.CData.__proto__ === ctypes.CType.prototype.
   1.931 +  // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the
   1.932 +  // prototype chain.)
   1.933 +  if (!JS_SetPrototype(cx, ctor, CTypeProto))
   1.934 +    return nullptr;
   1.935 +
   1.936 +  // Set up ctypes.CData.prototype.
   1.937 +  RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, NullPtr(), parent));
   1.938 +  if (!prototype)
   1.939 +    return nullptr;
   1.940 +
   1.941 +  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
   1.942 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   1.943 +    return nullptr;
   1.944 +
   1.945 +  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
   1.946 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   1.947 +    return nullptr;
   1.948 +
   1.949 +  // Define properties and functions common to all CDatas.
   1.950 +  if (!JS_DefineProperties(cx, prototype, sCDataProps) ||
   1.951 +      !JS_DefineFunctions(cx, prototype, sCDataFunctions))
   1.952 +    return nullptr;
   1.953 +
   1.954 +  if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
   1.955 +      !JS_FreezeObject(cx, ctor))
   1.956 +    return nullptr;
   1.957 +
   1.958 +  return prototype;
   1.959 +}
   1.960 +
   1.961 +static bool
   1.962 +DefineABIConstant(JSContext* cx,
   1.963 +                  HandleObject parent,
   1.964 +                  const char* name,
   1.965 +                  ABICode code,
   1.966 +                  HandleObject prototype)
   1.967 +{
   1.968 +  RootedObject obj(cx, JS_DefineObject(cx, parent, name, &sCABIClass, prototype,
   1.969 +                                       JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT));
   1.970 +  if (!obj)
   1.971 +    return false;
   1.972 +  JS_SetReservedSlot(obj, SLOT_ABICODE, INT_TO_JSVAL(code));
   1.973 +  return JS_FreezeObject(cx, obj);
   1.974 +}
   1.975 +
   1.976 +// Set up a single type constructor for
   1.977 +// ctypes.{Pointer,Array,Struct,Function}Type.
   1.978 +static bool
   1.979 +InitTypeConstructor(JSContext* cx,
   1.980 +                    HandleObject parent,
   1.981 +                    HandleObject CTypeProto,
   1.982 +                    HandleObject CDataProto,
   1.983 +                    const JSFunctionSpec spec,
   1.984 +                    const JSFunctionSpec* fns,
   1.985 +                    const JSPropertySpec* props,
   1.986 +                    const JSFunctionSpec* instanceFns,
   1.987 +                    const JSPropertySpec* instanceProps,
   1.988 +                    MutableHandleObject typeProto,
   1.989 +                    MutableHandleObject dataProto)
   1.990 +{
   1.991 +  JSFunction* fun = js::DefineFunctionWithReserved(cx, parent, spec.name, spec.call.op,
   1.992 +                      spec.nargs, spec.flags);
   1.993 +  if (!fun)
   1.994 +    return false;
   1.995 +
   1.996 +  RootedObject obj(cx, JS_GetFunctionObject(fun));
   1.997 +  if (!obj)
   1.998 +    return false;
   1.999 +
  1.1000 +  // Set up the .prototype and .prototype.constructor properties.
  1.1001 +  typeProto.set(JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent));
  1.1002 +  if (!typeProto)
  1.1003 +    return false;
  1.1004 +
  1.1005 +  // Define property before proceeding, for GC safety.
  1.1006 +  if (!JS_DefineProperty(cx, obj, "prototype", typeProto,
  1.1007 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1008 +    return false;
  1.1009 +
  1.1010 +  if (fns && !JS_DefineFunctions(cx, typeProto, fns))
  1.1011 +    return false;
  1.1012 +
  1.1013 +  if (!JS_DefineProperties(cx, typeProto, props))
  1.1014 +    return false;
  1.1015 +
  1.1016 +  if (!JS_DefineProperty(cx, typeProto, "constructor", obj,
  1.1017 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1018 +    return false;
  1.1019 +
  1.1020 +  // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
  1.1021 +  // the type constructor, for faster lookup.
  1.1022 +  js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
  1.1023 +
  1.1024 +  // Create an object to serve as the common ancestor for all CData objects
  1.1025 +  // created from the given type constructor. This has ctypes.CData.prototype
  1.1026 +  // as its prototype, such that it inherits the properties and functions
  1.1027 +  // common to all CDatas.
  1.1028 +  dataProto.set(JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent));
  1.1029 +  if (!dataProto)
  1.1030 +    return false;
  1.1031 +
  1.1032 +  // Define functions and properties on the 'dataProto' object that are common
  1.1033 +  // to all CData objects created from this type constructor. (These will
  1.1034 +  // become functions and properties on CData objects created from this type.)
  1.1035 +  if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns))
  1.1036 +    return false;
  1.1037 +
  1.1038 +  if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps))
  1.1039 +    return false;
  1.1040 +
  1.1041 +  // Link the type prototype to the data prototype.
  1.1042 +  JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(dataProto));
  1.1043 +
  1.1044 +  if (!JS_FreezeObject(cx, obj) ||
  1.1045 +      //!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
  1.1046 +      !JS_FreezeObject(cx, typeProto))
  1.1047 +    return false;
  1.1048 +
  1.1049 +  return true;
  1.1050 +}
  1.1051 +
  1.1052 +static JSObject*
  1.1053 +InitInt64Class(JSContext* cx,
  1.1054 +               HandleObject parent,
  1.1055 +               const JSClass* clasp,
  1.1056 +               JSNative construct,
  1.1057 +               const JSFunctionSpec* fs,
  1.1058 +               const JSFunctionSpec* static_fs)
  1.1059 +{
  1.1060 +  // Init type class and constructor
  1.1061 +  RootedObject prototype(cx, JS_InitClass(cx, parent, js::NullPtr(), clasp, construct,
  1.1062 +                                          0, nullptr, fs, nullptr, static_fs));
  1.1063 +  if (!prototype)
  1.1064 +    return nullptr;
  1.1065 +
  1.1066 +  RootedObject ctor(cx, JS_GetConstructor(cx, prototype));
  1.1067 +  if (!ctor)
  1.1068 +    return nullptr;
  1.1069 +  if (!JS_FreezeObject(cx, ctor))
  1.1070 +    return nullptr;
  1.1071 +
  1.1072 +  // Redefine the 'join' function as an extended native and stash
  1.1073 +  // ctypes.{Int64,UInt64}.prototype in a reserved slot of the new function.
  1.1074 +  JS_ASSERT(clasp == &sInt64ProtoClass || clasp == &sUInt64ProtoClass);
  1.1075 +  JSNative native = (clasp == &sInt64ProtoClass) ? Int64::Join : UInt64::Join;
  1.1076 +  JSFunction* fun = js::DefineFunctionWithReserved(cx, ctor, "join", native,
  1.1077 +                      2, CTYPESFN_FLAGS);
  1.1078 +  if (!fun)
  1.1079 +    return nullptr;
  1.1080 +
  1.1081 +  js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO,
  1.1082 +    OBJECT_TO_JSVAL(prototype));
  1.1083 +
  1.1084 +  if (!JS_FreezeObject(cx, prototype))
  1.1085 +    return nullptr;
  1.1086 +
  1.1087 +  return prototype;
  1.1088 +}
  1.1089 +
  1.1090 +static void
  1.1091 +AttachProtos(JSObject* proto, const AutoObjectVector& protos)
  1.1092 +{
  1.1093 +  // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos'
  1.1094 +  // to the appropriate CTypeProtoSlot. (SLOT_CTYPES is the last slot
  1.1095 +  // of [[Class]] "CTypeProto" that we fill in this automated manner.)
  1.1096 +  for (uint32_t i = 0; i <= SLOT_CTYPES; ++i)
  1.1097 +    JS_SetReservedSlot(proto, i, OBJECT_TO_JSVAL(protos[i]));
  1.1098 +}
  1.1099 +
  1.1100 +static bool
  1.1101 +InitTypeClasses(JSContext* cx, HandleObject parent)
  1.1102 +{
  1.1103 +  // Initialize the ctypes.CType class. This acts as an abstract base class for
  1.1104 +  // the various types, and provides the common API functions. It has:
  1.1105 +  //   * [[Class]] "Function"
  1.1106 +  //   * __proto__ === Function.prototype
  1.1107 +  //   * A constructor that throws a TypeError. (You can't construct an
  1.1108 +  //     abstract type!)
  1.1109 +  //   * 'prototype' property:
  1.1110 +  //     * [[Class]] "CTypeProto"
  1.1111 +  //     * __proto__ === Function.prototype
  1.1112 +  //     * A constructor that throws a TypeError. (You can't construct an
  1.1113 +  //       abstract type instance!)
  1.1114 +  //     * 'constructor' property === ctypes.CType
  1.1115 +  //     * Provides properties and functions common to all CTypes.
  1.1116 +  RootedObject CTypeProto(cx, InitCTypeClass(cx, parent));
  1.1117 +  if (!CTypeProto)
  1.1118 +    return false;
  1.1119 +
  1.1120 +  // Initialize the ctypes.CData class. This acts as an abstract base class for
  1.1121 +  // instances of the various types, and provides the common API functions.
  1.1122 +  // It has:
  1.1123 +  //   * [[Class]] "Function"
  1.1124 +  //   * __proto__ === Function.prototype
  1.1125 +  //   * A constructor that throws a TypeError. (You can't construct an
  1.1126 +  //     abstract type instance!)
  1.1127 +  //   * 'prototype' property:
  1.1128 +  //     * [[Class]] "CDataProto"
  1.1129 +  //     * 'constructor' property === ctypes.CData
  1.1130 +  //     * Provides properties and functions common to all CDatas.
  1.1131 +  RootedObject CDataProto(cx, InitCDataClass(cx, parent, CTypeProto));
  1.1132 +  if (!CDataProto)
  1.1133 +    return false;
  1.1134 +
  1.1135 +  // Link CTypeProto to CDataProto.
  1.1136 +  JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(CDataProto));
  1.1137 +
  1.1138 +  // Create and attach the special class constructors: ctypes.PointerType,
  1.1139 +  // ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType.
  1.1140 +  // Each of these constructors 'c' has, respectively:
  1.1141 +  //   * [[Class]] "Function"
  1.1142 +  //   * __proto__ === Function.prototype
  1.1143 +  //   * A constructor that creates a user-defined type.
  1.1144 +  //   * 'prototype' property:
  1.1145 +  //     * [[Class]] "CTypeProto"
  1.1146 +  //     * __proto__ === ctypes.CType.prototype
  1.1147 +  //     * 'constructor' property === 'c'
  1.1148 +  // We also construct an object 'p' to serve, given a type object 't'
  1.1149 +  // constructed from one of these type constructors, as
  1.1150 +  // 't.prototype.__proto__'. This object has:
  1.1151 +  //   * [[Class]] "CDataProto"
  1.1152 +  //   * __proto__ === ctypes.CData.prototype
  1.1153 +  //   * Properties and functions common to all CDatas.
  1.1154 +  // Therefore an instance 't' of ctypes.{Pointer,Array,Struct,Function}Type
  1.1155 +  // will have, resp.:
  1.1156 +  //   * [[Class]] "CType"
  1.1157 +  //   * __proto__ === ctypes.{Pointer,Array,Struct,Function}Type.prototype
  1.1158 +  //   * A constructor which creates and returns a CData object, containing
  1.1159 +  //     binary data of the given type.
  1.1160 +  //   * 'prototype' property:
  1.1161 +  //     * [[Class]] "CDataProto"
  1.1162 +  //     * __proto__ === 'p', the prototype object from above
  1.1163 +  //     * 'constructor' property === 't'
  1.1164 +  AutoObjectVector protos(cx);
  1.1165 +  protos.resize(CTYPEPROTO_SLOTS);
  1.1166 +  if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1.1167 +         sPointerFunction, nullptr, sPointerProps,
  1.1168 +         sPointerInstanceFunctions, sPointerInstanceProps,
  1.1169 +         protos.handleAt(SLOT_POINTERPROTO), protos.handleAt(SLOT_POINTERDATAPROTO)))
  1.1170 +    return false;
  1.1171 +
  1.1172 +  if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1.1173 +         sArrayFunction, nullptr, sArrayProps,
  1.1174 +         sArrayInstanceFunctions, sArrayInstanceProps,
  1.1175 +         protos.handleAt(SLOT_ARRAYPROTO), protos.handleAt(SLOT_ARRAYDATAPROTO)))
  1.1176 +    return false;
  1.1177 +
  1.1178 +  if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1.1179 +         sStructFunction, sStructFunctions, sStructProps,
  1.1180 +         sStructInstanceFunctions, nullptr,
  1.1181 +         protos.handleAt(SLOT_STRUCTPROTO), protos.handleAt(SLOT_STRUCTDATAPROTO)))
  1.1182 +    return false;
  1.1183 +
  1.1184 +  if (!InitTypeConstructor(cx, parent, CTypeProto, protos.handleAt(SLOT_POINTERDATAPROTO),
  1.1185 +         sFunctionFunction, nullptr, sFunctionProps, sFunctionInstanceFunctions, nullptr,
  1.1186 +         protos.handleAt(SLOT_FUNCTIONPROTO), protos.handleAt(SLOT_FUNCTIONDATAPROTO)))
  1.1187 +    return false;
  1.1188 +
  1.1189 +  protos[SLOT_CDATAPROTO] = CDataProto;
  1.1190 +
  1.1191 +  // Create and attach the ctypes.{Int64,UInt64} constructors.
  1.1192 +  // Each of these has, respectively:
  1.1193 +  //   * [[Class]] "Function"
  1.1194 +  //   * __proto__ === Function.prototype
  1.1195 +  //   * A constructor that creates a ctypes.{Int64,UInt64} object, respectively.
  1.1196 +  //   * 'prototype' property:
  1.1197 +  //     * [[Class]] {"Int64Proto","UInt64Proto"}
  1.1198 +  //     * 'constructor' property === ctypes.{Int64,UInt64}
  1.1199 +  protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass,
  1.1200 +    Int64::Construct, sInt64Functions, sInt64StaticFunctions);
  1.1201 +  if (!protos[SLOT_INT64PROTO])
  1.1202 +    return false;
  1.1203 +  protos[SLOT_UINT64PROTO] = InitInt64Class(cx, parent, &sUInt64ProtoClass,
  1.1204 +    UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions);
  1.1205 +  if (!protos[SLOT_UINT64PROTO])
  1.1206 +    return false;
  1.1207 +
  1.1208 +  // Finally, store a pointer to the global ctypes object.
  1.1209 +  // Note that there is no other reliable manner of locating this object.
  1.1210 +  protos[SLOT_CTYPES] = parent;
  1.1211 +
  1.1212 +  // Attach the prototypes just created to each of ctypes.CType.prototype,
  1.1213 +  // and the special type constructors, so we can access them when constructing
  1.1214 +  // instances of those types.
  1.1215 +  AttachProtos(CTypeProto, protos);
  1.1216 +  AttachProtos(protos[SLOT_POINTERPROTO], protos);
  1.1217 +  AttachProtos(protos[SLOT_ARRAYPROTO], protos);
  1.1218 +  AttachProtos(protos[SLOT_STRUCTPROTO], protos);
  1.1219 +  AttachProtos(protos[SLOT_FUNCTIONPROTO], protos);
  1.1220 +
  1.1221 +  RootedObject ABIProto(cx, InitABIClass(cx, parent));
  1.1222 +  if (!ABIProto)
  1.1223 +    return false;
  1.1224 +
  1.1225 +  // Attach objects representing ABI constants.
  1.1226 +  if (!DefineABIConstant(cx, parent, "default_abi", ABI_DEFAULT, ABIProto) ||
  1.1227 +      !DefineABIConstant(cx, parent, "stdcall_abi", ABI_STDCALL, ABIProto) ||
  1.1228 +      !DefineABIConstant(cx, parent, "winapi_abi", ABI_WINAPI, ABIProto))
  1.1229 +    return false;
  1.1230 +
  1.1231 +  // Create objects representing the builtin types, and attach them to the
  1.1232 +  // ctypes object. Each type object 't' has:
  1.1233 +  //   * [[Class]] "CType"
  1.1234 +  //   * __proto__ === ctypes.CType.prototype
  1.1235 +  //   * A constructor which creates and returns a CData object, containing
  1.1236 +  //     binary data of the given type.
  1.1237 +  //   * 'prototype' property:
  1.1238 +  //     * [[Class]] "CDataProto"
  1.1239 +  //     * __proto__ === ctypes.CData.prototype
  1.1240 +  //     * 'constructor' property === 't'
  1.1241 +#define DEFINE_TYPE(name, type, ffiType)                                       \
  1.1242 +  RootedObject typeObj_##name(cx,                                              \
  1.1243 +    CType::DefineBuiltin(cx, parent, #name, CTypeProto, CDataProto, #name,     \
  1.1244 +      TYPE_##name, INT_TO_JSVAL(sizeof(type)),                                 \
  1.1245 +      INT_TO_JSVAL(ffiType.alignment), &ffiType));                             \
  1.1246 +  if (!typeObj_##name)                                                         \
  1.1247 +    return false;
  1.1248 +#include "ctypes/typedefs.h"
  1.1249 +
  1.1250 +  // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
  1.1251 +  // the same type in C.
  1.1252 +  if (!JS_DefineProperty(cx, parent, "unsigned", typeObj_unsigned_int,
  1.1253 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1254 +    return false;
  1.1255 +
  1.1256 +  // Create objects representing the special types void_t and voidptr_t.
  1.1257 +  RootedObject typeObj(cx,
  1.1258 +    CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void",
  1.1259 +                         TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void));
  1.1260 +  if (!typeObj)
  1.1261 +    return false;
  1.1262 +
  1.1263 +  typeObj = PointerType::CreateInternal(cx, typeObj);
  1.1264 +  if (!typeObj)
  1.1265 +    return false;
  1.1266 +  if (!JS_DefineProperty(cx, parent, "voidptr_t", typeObj,
  1.1267 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1268 +    return false;
  1.1269 +
  1.1270 +  return true;
  1.1271 +}
  1.1272 +
  1.1273 +bool
  1.1274 +IsCTypesGlobal(JSObject* obj)
  1.1275 +{
  1.1276 +  return JS_GetClass(obj) == &sCTypesGlobalClass;
  1.1277 +}
  1.1278 +
  1.1279 +bool
  1.1280 +IsCTypesGlobal(HandleValue v)
  1.1281 +{
  1.1282 +  return v.isObject() && IsCTypesGlobal(&v.toObject());
  1.1283 +}
  1.1284 +
  1.1285 +// Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'.
  1.1286 +JSCTypesCallbacks*
  1.1287 +GetCallbacks(JSObject* obj)
  1.1288 +{
  1.1289 +  JS_ASSERT(IsCTypesGlobal(obj));
  1.1290 +
  1.1291 +  jsval result = JS_GetReservedSlot(obj, SLOT_CALLBACKS);
  1.1292 +  if (JSVAL_IS_VOID(result))
  1.1293 +    return nullptr;
  1.1294 +
  1.1295 +  return static_cast<JSCTypesCallbacks*>(JSVAL_TO_PRIVATE(result));
  1.1296 +}
  1.1297 +
  1.1298 +// Utility function to access a property of an object as an object
  1.1299 +// returns false and sets the error if the property does not exist
  1.1300 +// or is not an object
  1.1301 +static bool GetObjectProperty(JSContext *cx, HandleObject obj,
  1.1302 +                              const char *property, MutableHandleObject result)
  1.1303 +{
  1.1304 +  RootedValue val(cx);
  1.1305 +  if (!JS_GetProperty(cx, obj, property, &val)) {
  1.1306 +    return false;
  1.1307 +  }
  1.1308 +
  1.1309 +  if (JSVAL_IS_PRIMITIVE(val)) {
  1.1310 +    JS_ReportError(cx, "missing or non-object field");
  1.1311 +    return false;
  1.1312 +  }
  1.1313 +
  1.1314 +  result.set(JSVAL_TO_OBJECT(val));
  1.1315 +  return true;
  1.1316 +}
  1.1317 +
  1.1318 +} /* namespace ctypes */
  1.1319 +} /* namespace js */
  1.1320 +
  1.1321 +using namespace js;
  1.1322 +using namespace js::ctypes;
  1.1323 +
  1.1324 +JS_PUBLIC_API(bool)
  1.1325 +JS_InitCTypesClass(JSContext* cx, HandleObject global)
  1.1326 +{
  1.1327 +  // attach ctypes property to global object
  1.1328 +  RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass, NullPtr(), NullPtr()));
  1.1329 +  if (!ctypes)
  1.1330 +    return false;
  1.1331 +
  1.1332 +  if (!JS_DefineProperty(cx, global, "ctypes", ctypes, JSPROP_READONLY | JSPROP_PERMANENT,
  1.1333 +                         JS_PropertyStub, JS_StrictPropertyStub)){
  1.1334 +    return false;
  1.1335 +  }
  1.1336 +
  1.1337 +  if (!InitTypeClasses(cx, ctypes))
  1.1338 +    return false;
  1.1339 +
  1.1340 +  // attach API functions and properties
  1.1341 +  if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions) ||
  1.1342 +      !JS_DefineProperties(cx, ctypes, sModuleProps))
  1.1343 +    return false;
  1.1344 +
  1.1345 +  // Set up ctypes.CDataFinalizer.prototype.
  1.1346 +  RootedObject ctor(cx);
  1.1347 +  if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor))
  1.1348 +    return false;
  1.1349 +
  1.1350 +  RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, NullPtr(), ctypes));
  1.1351 +  if (!prototype)
  1.1352 +    return false;
  1.1353 +
  1.1354 +  if (!JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions))
  1.1355 +    return false;
  1.1356 +
  1.1357 +  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
  1.1358 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1359 +    return false;
  1.1360 +
  1.1361 +  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
  1.1362 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.1363 +    return false;
  1.1364 +
  1.1365 +
  1.1366 +  // Seal the ctypes object, to prevent modification.
  1.1367 +  return JS_FreezeObject(cx, ctypes);
  1.1368 +}
  1.1369 +
  1.1370 +JS_PUBLIC_API(void)
  1.1371 +JS_SetCTypesCallbacks(JSObject *ctypesObj, JSCTypesCallbacks* callbacks)
  1.1372 +{
  1.1373 +  JS_ASSERT(callbacks);
  1.1374 +  JS_ASSERT(IsCTypesGlobal(ctypesObj));
  1.1375 +
  1.1376 +  // Set the callbacks on a reserved slot.
  1.1377 +  JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS, PRIVATE_TO_JSVAL(callbacks));
  1.1378 +}
  1.1379 +
  1.1380 +namespace js {
  1.1381 +
  1.1382 +JS_FRIEND_API(size_t)
  1.1383 +SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject *obj)
  1.1384 +{
  1.1385 +    if (!CData::IsCData(obj))
  1.1386 +        return 0;
  1.1387 +
  1.1388 +    size_t n = 0;
  1.1389 +    jsval slot = JS_GetReservedSlot(obj, ctypes::SLOT_OWNS);
  1.1390 +    if (!JSVAL_IS_VOID(slot)) {
  1.1391 +        bool owns = JSVAL_TO_BOOLEAN(slot);
  1.1392 +        slot = JS_GetReservedSlot(obj, ctypes::SLOT_DATA);
  1.1393 +        if (!JSVAL_IS_VOID(slot)) {
  1.1394 +            char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
  1.1395 +            n += mallocSizeOf(buffer);
  1.1396 +            if (owns)
  1.1397 +                n += mallocSizeOf(*buffer);
  1.1398 +        }
  1.1399 +    }
  1.1400 +    return n;
  1.1401 +}
  1.1402 +
  1.1403 +namespace ctypes {
  1.1404 +
  1.1405 +/*******************************************************************************
  1.1406 +** Type conversion functions
  1.1407 +*******************************************************************************/
  1.1408 +
  1.1409 +// Enforce some sanity checks on type widths and properties.
  1.1410 +// Where the architecture is 64-bit, make sure it's LP64 or LLP64. (ctypes.int
  1.1411 +// autoconverts to a primitive JS number; to support ILP64 architectures, it
  1.1412 +// would need to autoconvert to an Int64 object instead. Therefore we enforce
  1.1413 +// this invariant here.)
  1.1414 +JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4);
  1.1415 +JS_STATIC_ASSERT(sizeof(char) == 1);
  1.1416 +JS_STATIC_ASSERT(sizeof(short) == 2);
  1.1417 +JS_STATIC_ASSERT(sizeof(int) == 4);
  1.1418 +JS_STATIC_ASSERT(sizeof(unsigned) == 4);
  1.1419 +JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
  1.1420 +JS_STATIC_ASSERT(sizeof(long long) == 8);
  1.1421 +JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
  1.1422 +JS_STATIC_ASSERT(sizeof(float) == 4);
  1.1423 +JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
  1.1424 +JS_STATIC_ASSERT(NumericLimits<double>::is_signed);
  1.1425 +
  1.1426 +// Templated helper to convert FromType to TargetType, for the default case
  1.1427 +// where the trivial POD constructor will do.
  1.1428 +template<class TargetType, class FromType>
  1.1429 +struct ConvertImpl {
  1.1430 +  static MOZ_ALWAYS_INLINE TargetType Convert(FromType d) {
  1.1431 +    return TargetType(d);
  1.1432 +  }
  1.1433 +};
  1.1434 +
  1.1435 +#ifdef _MSC_VER
  1.1436 +// MSVC can't perform double to unsigned __int64 conversion when the
  1.1437 +// double is greater than 2^63 - 1. Help it along a little.
  1.1438 +template<>
  1.1439 +struct ConvertImpl<uint64_t, double> {
  1.1440 +  static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
  1.1441 +    return d > 0x7fffffffffffffffui64 ?
  1.1442 +           uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
  1.1443 +           uint64_t(d);
  1.1444 +  }
  1.1445 +};
  1.1446 +#endif
  1.1447 +
  1.1448 +// C++ doesn't guarantee that exact values are the only ones that will
  1.1449 +// round-trip. In fact, on some platforms, including SPARC, there are pairs of
  1.1450 +// values, a uint64_t and a double, such that neither value is exactly
  1.1451 +// representable in the other type, but they cast to each other.
  1.1452 +#if defined(SPARC) || defined(__powerpc__)
  1.1453 +// Simulate x86 overflow behavior
  1.1454 +template<>
  1.1455 +struct ConvertImpl<uint64_t, double> {
  1.1456 +  static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
  1.1457 +    return d >= 0xffffffffffffffff ?
  1.1458 +           0x8000000000000000 : uint64_t(d);
  1.1459 +  }
  1.1460 +};
  1.1461 +
  1.1462 +template<>
  1.1463 +struct ConvertImpl<int64_t, double> {
  1.1464 +  static MOZ_ALWAYS_INLINE int64_t Convert(double d) {
  1.1465 +    return d >= 0x7fffffffffffffff ?
  1.1466 +           0x8000000000000000 : int64_t(d);
  1.1467 +  }
  1.1468 +};
  1.1469 +#endif
  1.1470 +
  1.1471 +template<class TargetType, class FromType>
  1.1472 +static MOZ_ALWAYS_INLINE TargetType Convert(FromType d)
  1.1473 +{
  1.1474 +  return ConvertImpl<TargetType, FromType>::Convert(d);
  1.1475 +}
  1.1476 +
  1.1477 +template<class TargetType, class FromType>
  1.1478 +static MOZ_ALWAYS_INLINE bool IsAlwaysExact()
  1.1479 +{
  1.1480 +  // Return 'true' if TargetType can always exactly represent FromType.
  1.1481 +  // This means that:
  1.1482 +  // 1) TargetType must be the same or more bits wide as FromType. For integers
  1.1483 +  //    represented in 'n' bits, unsigned variants will have 'n' digits while
  1.1484 +  //    signed will have 'n - 1'. For floating point types, 'digits' is the
  1.1485 +  //    mantissa width.
  1.1486 +  // 2) If FromType is signed, TargetType must also be signed. (Floating point
  1.1487 +  //    types are always signed.)
  1.1488 +  // 3) If TargetType is an exact integral type, FromType must be also.
  1.1489 +  if (NumericLimits<TargetType>::digits < NumericLimits<FromType>::digits)
  1.1490 +    return false;
  1.1491 +
  1.1492 +  if (NumericLimits<FromType>::is_signed &&
  1.1493 +      !NumericLimits<TargetType>::is_signed)
  1.1494 +    return false;
  1.1495 +
  1.1496 +  if (!NumericLimits<FromType>::is_exact &&
  1.1497 +      NumericLimits<TargetType>::is_exact)
  1.1498 +    return false;
  1.1499 +
  1.1500 +  return true;
  1.1501 +}
  1.1502 +
  1.1503 +// Templated helper to determine if FromType 'i' converts losslessly to
  1.1504 +// TargetType 'j'. Default case where both types are the same signedness.
  1.1505 +template<class TargetType, class FromType, bool TargetSigned, bool FromSigned>
  1.1506 +struct IsExactImpl {
  1.1507 +  static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1.1508 +    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1.1509 +    return FromType(j) == i;
  1.1510 +  }
  1.1511 +};
  1.1512 +
  1.1513 +// Specialization where TargetType is unsigned, FromType is signed.
  1.1514 +template<class TargetType, class FromType>
  1.1515 +struct IsExactImpl<TargetType, FromType, false, true> {
  1.1516 +  static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1.1517 +    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1.1518 +    return i >= 0 && FromType(j) == i;
  1.1519 +  }
  1.1520 +};
  1.1521 +
  1.1522 +// Specialization where TargetType is signed, FromType is unsigned.
  1.1523 +template<class TargetType, class FromType>
  1.1524 +struct IsExactImpl<TargetType, FromType, true, false> {
  1.1525 +  static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1.1526 +    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1.1527 +    return TargetType(i) >= 0 && FromType(j) == i;
  1.1528 +  }
  1.1529 +};
  1.1530 +
  1.1531 +// Convert FromType 'i' to TargetType 'result', returning true iff 'result'
  1.1532 +// is an exact representation of 'i'.
  1.1533 +template<class TargetType, class FromType>
  1.1534 +static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
  1.1535 +{
  1.1536 +  // Require that TargetType is integral, to simplify conversion.
  1.1537 +  JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1.1538 +
  1.1539 +  *result = Convert<TargetType>(i);
  1.1540 +
  1.1541 +  // See if we can avoid a dynamic check.
  1.1542 +  if (IsAlwaysExact<TargetType, FromType>())
  1.1543 +    return true;
  1.1544 +
  1.1545 +  // Return 'true' if 'i' is exactly representable in 'TargetType'.
  1.1546 +  return IsExactImpl<TargetType,
  1.1547 +                     FromType,
  1.1548 +                     NumericLimits<TargetType>::is_signed,
  1.1549 +                     NumericLimits<FromType>::is_signed>::Test(i, *result);
  1.1550 +}
  1.1551 +
  1.1552 +// Templated helper to determine if Type 'i' is negative. Default case
  1.1553 +// where IntegerType is unsigned.
  1.1554 +template<class Type, bool IsSigned>
  1.1555 +struct IsNegativeImpl {
  1.1556 +  static MOZ_ALWAYS_INLINE bool Test(Type i) {
  1.1557 +    return false;
  1.1558 +  }
  1.1559 +};
  1.1560 +
  1.1561 +// Specialization where Type is signed.
  1.1562 +template<class Type>
  1.1563 +struct IsNegativeImpl<Type, true> {
  1.1564 +  static MOZ_ALWAYS_INLINE bool Test(Type i) {
  1.1565 +    return i < 0;
  1.1566 +  }
  1.1567 +};
  1.1568 +
  1.1569 +// Determine whether Type 'i' is negative.
  1.1570 +template<class Type>
  1.1571 +static MOZ_ALWAYS_INLINE bool IsNegative(Type i)
  1.1572 +{
  1.1573 +  return IsNegativeImpl<Type, NumericLimits<Type>::is_signed>::Test(i);
  1.1574 +}
  1.1575 +
  1.1576 +// Implicitly convert val to bool, allowing bool, int, and double
  1.1577 +// arguments numerically equal to 0 or 1.
  1.1578 +static bool
  1.1579 +jsvalToBool(JSContext* cx, jsval val, bool* result)
  1.1580 +{
  1.1581 +  if (JSVAL_IS_BOOLEAN(val)) {
  1.1582 +    *result = JSVAL_TO_BOOLEAN(val);
  1.1583 +    return true;
  1.1584 +  }
  1.1585 +  if (JSVAL_IS_INT(val)) {
  1.1586 +    int32_t i = JSVAL_TO_INT(val);
  1.1587 +    *result = i != 0;
  1.1588 +    return i == 0 || i == 1;
  1.1589 +  }
  1.1590 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1591 +    double d = JSVAL_TO_DOUBLE(val);
  1.1592 +    *result = d != 0;
  1.1593 +    // Allow -0.
  1.1594 +    return d == 1 || d == 0;
  1.1595 +  }
  1.1596 +  // Don't silently convert null to bool. It's probably a mistake.
  1.1597 +  return false;
  1.1598 +}
  1.1599 +
  1.1600 +// Implicitly convert val to IntegerType, allowing bool, int, double,
  1.1601 +// Int64, UInt64, and CData integer types 't' where all values of 't' are
  1.1602 +// representable by IntegerType.
  1.1603 +template<class IntegerType>
  1.1604 +static bool
  1.1605 +jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
  1.1606 +{
  1.1607 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.1608 +
  1.1609 +  if (JSVAL_IS_INT(val)) {
  1.1610 +    // Make sure the integer fits in the alotted precision, and has the right
  1.1611 +    // sign.
  1.1612 +    int32_t i = JSVAL_TO_INT(val);
  1.1613 +    return ConvertExact(i, result);
  1.1614 +  }
  1.1615 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1616 +    // Don't silently lose bits here -- check that val really is an
  1.1617 +    // integer value, and has the right sign.
  1.1618 +    double d = JSVAL_TO_DOUBLE(val);
  1.1619 +    return ConvertExact(d, result);
  1.1620 +  }
  1.1621 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.1622 +    JSObject* obj = JSVAL_TO_OBJECT(val);
  1.1623 +    if (CData::IsCData(obj)) {
  1.1624 +      JSObject* typeObj = CData::GetCType(obj);
  1.1625 +      void* data = CData::GetData(obj);
  1.1626 +
  1.1627 +      // Check whether the source type is always representable, with exact
  1.1628 +      // precision, by the target type. If it is, convert the value.
  1.1629 +      switch (CType::GetTypeCode(typeObj)) {
  1.1630 +#define DEFINE_INT_TYPE(name, fromType, ffiType)                               \
  1.1631 +      case TYPE_##name:                                                        \
  1.1632 +        if (!IsAlwaysExact<IntegerType, fromType>())                           \
  1.1633 +          return false;                                                        \
  1.1634 +        *result = IntegerType(*static_cast<fromType*>(data));                  \
  1.1635 +        return true;
  1.1636 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.1637 +#include "ctypes/typedefs.h"
  1.1638 +      case TYPE_void_t:
  1.1639 +      case TYPE_bool:
  1.1640 +      case TYPE_float:
  1.1641 +      case TYPE_double:
  1.1642 +      case TYPE_float32_t:
  1.1643 +      case TYPE_float64_t:
  1.1644 +      case TYPE_char:
  1.1645 +      case TYPE_signed_char:
  1.1646 +      case TYPE_unsigned_char:
  1.1647 +      case TYPE_jschar:
  1.1648 +      case TYPE_pointer:
  1.1649 +      case TYPE_function:
  1.1650 +      case TYPE_array:
  1.1651 +      case TYPE_struct:
  1.1652 +        // Not a compatible number type.
  1.1653 +        return false;
  1.1654 +      }
  1.1655 +    }
  1.1656 +
  1.1657 +    if (Int64::IsInt64(obj)) {
  1.1658 +      // Make sure the integer fits in IntegerType.
  1.1659 +      int64_t i = Int64Base::GetInt(obj);
  1.1660 +      return ConvertExact(i, result);
  1.1661 +    }
  1.1662 +
  1.1663 +    if (UInt64::IsUInt64(obj)) {
  1.1664 +      // Make sure the integer fits in IntegerType.
  1.1665 +      uint64_t i = Int64Base::GetInt(obj);
  1.1666 +      return ConvertExact(i, result);
  1.1667 +    }
  1.1668 +
  1.1669 +    if (CDataFinalizer::IsCDataFinalizer(obj)) {
  1.1670 +      RootedValue innerData(cx);
  1.1671 +      if (!CDataFinalizer::GetValue(cx, obj, innerData.address())) {
  1.1672 +        return false; // Nothing to convert
  1.1673 +      }
  1.1674 +      return jsvalToInteger(cx, innerData, result);
  1.1675 +    }
  1.1676 +
  1.1677 +    return false;
  1.1678 +  }
  1.1679 +  if (JSVAL_IS_BOOLEAN(val)) {
  1.1680 +    // Implicitly promote boolean values to 0 or 1, like C.
  1.1681 +    *result = JSVAL_TO_BOOLEAN(val);
  1.1682 +    JS_ASSERT(*result == 0 || *result == 1);
  1.1683 +    return true;
  1.1684 +  }
  1.1685 +  // Don't silently convert null to an integer. It's probably a mistake.
  1.1686 +  return false;
  1.1687 +}
  1.1688 +
  1.1689 +// Implicitly convert val to FloatType, allowing int, double,
  1.1690 +// Int64, UInt64, and CData numeric types 't' where all values of 't' are
  1.1691 +// representable by FloatType.
  1.1692 +template<class FloatType>
  1.1693 +static bool
  1.1694 +jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
  1.1695 +{
  1.1696 +  JS_STATIC_ASSERT(!NumericLimits<FloatType>::is_exact);
  1.1697 +
  1.1698 +  // The following casts may silently throw away some bits, but there's
  1.1699 +  // no good way around it. Sternly requiring that the 64-bit double
  1.1700 +  // argument be exactly representable as a 32-bit float is
  1.1701 +  // unrealistic: it would allow 1/2 to pass but not 1/3.
  1.1702 +  if (JSVAL_IS_INT(val)) {
  1.1703 +    *result = FloatType(JSVAL_TO_INT(val));
  1.1704 +    return true;
  1.1705 +  }
  1.1706 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1707 +    *result = FloatType(JSVAL_TO_DOUBLE(val));
  1.1708 +    return true;
  1.1709 +  }
  1.1710 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.1711 +    JSObject* obj = JSVAL_TO_OBJECT(val);
  1.1712 +    if (CData::IsCData(obj)) {
  1.1713 +      JSObject* typeObj = CData::GetCType(obj);
  1.1714 +      void* data = CData::GetData(obj);
  1.1715 +
  1.1716 +      // Check whether the source type is always representable, with exact
  1.1717 +      // precision, by the target type. If it is, convert the value.
  1.1718 +      switch (CType::GetTypeCode(typeObj)) {
  1.1719 +#define DEFINE_FLOAT_TYPE(name, fromType, ffiType)                             \
  1.1720 +      case TYPE_##name:                                                        \
  1.1721 +        if (!IsAlwaysExact<FloatType, fromType>())                             \
  1.1722 +          return false;                                                        \
  1.1723 +        *result = FloatType(*static_cast<fromType*>(data));                    \
  1.1724 +        return true;
  1.1725 +#define DEFINE_INT_TYPE(x, y, z) DEFINE_FLOAT_TYPE(x, y, z)
  1.1726 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.1727 +#include "ctypes/typedefs.h"
  1.1728 +      case TYPE_void_t:
  1.1729 +      case TYPE_bool:
  1.1730 +      case TYPE_char:
  1.1731 +      case TYPE_signed_char:
  1.1732 +      case TYPE_unsigned_char:
  1.1733 +      case TYPE_jschar:
  1.1734 +      case TYPE_pointer:
  1.1735 +      case TYPE_function:
  1.1736 +      case TYPE_array:
  1.1737 +      case TYPE_struct:
  1.1738 +        // Not a compatible number type.
  1.1739 +        return false;
  1.1740 +      }
  1.1741 +    }
  1.1742 +  }
  1.1743 +  // Don't silently convert true to 1.0 or false to 0.0, even though C/C++
  1.1744 +  // does it. It's likely to be a mistake.
  1.1745 +  return false;
  1.1746 +}
  1.1747 +
  1.1748 +template<class IntegerType>
  1.1749 +static bool
  1.1750 +StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
  1.1751 +{
  1.1752 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.1753 +
  1.1754 +  const jschar* cp = string->getChars(nullptr);
  1.1755 +  if (!cp)
  1.1756 +    return false;
  1.1757 +
  1.1758 +  const jschar* end = cp + string->length();
  1.1759 +  if (cp == end)
  1.1760 +    return false;
  1.1761 +
  1.1762 +  IntegerType sign = 1;
  1.1763 +  if (cp[0] == '-') {
  1.1764 +    if (!NumericLimits<IntegerType>::is_signed)
  1.1765 +      return false;
  1.1766 +
  1.1767 +    sign = -1;
  1.1768 +    ++cp;
  1.1769 +  }
  1.1770 +
  1.1771 +  // Assume base-10, unless the string begins with '0x' or '0X'.
  1.1772 +  IntegerType base = 10;
  1.1773 +  if (end - cp > 2 && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) {
  1.1774 +    cp += 2;
  1.1775 +    base = 16;
  1.1776 +  }
  1.1777 +
  1.1778 +  // Scan the string left to right and build the number,
  1.1779 +  // checking for valid characters 0 - 9, a - f, A - F and overflow.
  1.1780 +  IntegerType i = 0;
  1.1781 +  while (cp != end) {
  1.1782 +    jschar c = *cp++;
  1.1783 +    if (c >= '0' && c <= '9')
  1.1784 +      c -= '0';
  1.1785 +    else if (base == 16 && c >= 'a' && c <= 'f')
  1.1786 +      c = c - 'a' + 10;
  1.1787 +    else if (base == 16 && c >= 'A' && c <= 'F')
  1.1788 +      c = c - 'A' + 10;
  1.1789 +    else
  1.1790 +      return false;
  1.1791 +
  1.1792 +    IntegerType ii = i;
  1.1793 +    i = ii * base + sign * c;
  1.1794 +    if (i / base != ii) // overflow
  1.1795 +      return false;
  1.1796 +  }
  1.1797 +
  1.1798 +  *result = i;
  1.1799 +  return true;
  1.1800 +}
  1.1801 +
  1.1802 +// Implicitly convert val to IntegerType, allowing int, double,
  1.1803 +// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
  1.1804 +// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
  1.1805 +template<class IntegerType>
  1.1806 +static bool
  1.1807 +jsvalToBigInteger(JSContext* cx,
  1.1808 +                  jsval val,
  1.1809 +                  bool allowString,
  1.1810 +                  IntegerType* result)
  1.1811 +{
  1.1812 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.1813 +
  1.1814 +  if (JSVAL_IS_INT(val)) {
  1.1815 +    // Make sure the integer fits in the alotted precision, and has the right
  1.1816 +    // sign.
  1.1817 +    int32_t i = JSVAL_TO_INT(val);
  1.1818 +    return ConvertExact(i, result);
  1.1819 +  }
  1.1820 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1821 +    // Don't silently lose bits here -- check that val really is an
  1.1822 +    // integer value, and has the right sign.
  1.1823 +    double d = JSVAL_TO_DOUBLE(val);
  1.1824 +    return ConvertExact(d, result);
  1.1825 +  }
  1.1826 +  if (allowString && JSVAL_IS_STRING(val)) {
  1.1827 +    // Allow conversion from base-10 or base-16 strings, provided the result
  1.1828 +    // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
  1.1829 +    // to the JS array element operator, which will automatically call
  1.1830 +    // toString() on the object for us.)
  1.1831 +    return StringToInteger(cx, JSVAL_TO_STRING(val), result);
  1.1832 +  }
  1.1833 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.1834 +    // Allow conversion from an Int64 or UInt64 object directly.
  1.1835 +    JSObject* obj = JSVAL_TO_OBJECT(val);
  1.1836 +
  1.1837 +    if (UInt64::IsUInt64(obj)) {
  1.1838 +      // Make sure the integer fits in IntegerType.
  1.1839 +      uint64_t i = Int64Base::GetInt(obj);
  1.1840 +      return ConvertExact(i, result);
  1.1841 +    }
  1.1842 +
  1.1843 +    if (Int64::IsInt64(obj)) {
  1.1844 +      // Make sure the integer fits in IntegerType.
  1.1845 +      int64_t i = Int64Base::GetInt(obj);
  1.1846 +      return ConvertExact(i, result);
  1.1847 +    }
  1.1848 +
  1.1849 +    if (CDataFinalizer::IsCDataFinalizer(obj)) {
  1.1850 +      RootedValue innerData(cx);
  1.1851 +      if (!CDataFinalizer::GetValue(cx, obj, innerData.address())) {
  1.1852 +        return false; // Nothing to convert
  1.1853 +      }
  1.1854 +      return jsvalToBigInteger(cx, innerData, allowString, result);
  1.1855 +    }
  1.1856 +
  1.1857 +  }
  1.1858 +  return false;
  1.1859 +}
  1.1860 +
  1.1861 +// Implicitly convert val to a size value, where the size value is represented
  1.1862 +// by size_t but must also fit in a double.
  1.1863 +static bool
  1.1864 +jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result)
  1.1865 +{
  1.1866 +  if (!jsvalToBigInteger(cx, val, allowString, result))
  1.1867 +    return false;
  1.1868 +
  1.1869 +  // Also check that the result fits in a double.
  1.1870 +  return Convert<size_t>(double(*result)) == *result;
  1.1871 +}
  1.1872 +
  1.1873 +// Implicitly convert val to IntegerType, allowing int, double,
  1.1874 +// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
  1.1875 +// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
  1.1876 +template<class IntegerType>
  1.1877 +static bool
  1.1878 +jsidToBigInteger(JSContext* cx,
  1.1879 +                  jsid val,
  1.1880 +                  bool allowString,
  1.1881 +                  IntegerType* result)
  1.1882 +{
  1.1883 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.1884 +
  1.1885 +  if (JSID_IS_INT(val)) {
  1.1886 +    // Make sure the integer fits in the alotted precision, and has the right
  1.1887 +    // sign.
  1.1888 +    int32_t i = JSID_TO_INT(val);
  1.1889 +    return ConvertExact(i, result);
  1.1890 +  }
  1.1891 +  if (allowString && JSID_IS_STRING(val)) {
  1.1892 +    // Allow conversion from base-10 or base-16 strings, provided the result
  1.1893 +    // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
  1.1894 +    // to the JS array element operator, which will automatically call
  1.1895 +    // toString() on the object for us.)
  1.1896 +    return StringToInteger(cx, JSID_TO_STRING(val), result);
  1.1897 +  }
  1.1898 +  if (JSID_IS_OBJECT(val)) {
  1.1899 +    // Allow conversion from an Int64 or UInt64 object directly.
  1.1900 +    JSObject* obj = JSID_TO_OBJECT(val);
  1.1901 +
  1.1902 +    if (UInt64::IsUInt64(obj)) {
  1.1903 +      // Make sure the integer fits in IntegerType.
  1.1904 +      uint64_t i = Int64Base::GetInt(obj);
  1.1905 +      return ConvertExact(i, result);
  1.1906 +    }
  1.1907 +
  1.1908 +    if (Int64::IsInt64(obj)) {
  1.1909 +      // Make sure the integer fits in IntegerType.
  1.1910 +      int64_t i = Int64Base::GetInt(obj);
  1.1911 +      return ConvertExact(i, result);
  1.1912 +    }
  1.1913 +  }
  1.1914 +  return false;
  1.1915 +}
  1.1916 +
  1.1917 +// Implicitly convert val to a size value, where the size value is represented
  1.1918 +// by size_t but must also fit in a double.
  1.1919 +static bool
  1.1920 +jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result)
  1.1921 +{
  1.1922 +  if (!jsidToBigInteger(cx, val, allowString, result))
  1.1923 +    return false;
  1.1924 +
  1.1925 +  // Also check that the result fits in a double.
  1.1926 +  return Convert<size_t>(double(*result)) == *result;
  1.1927 +}
  1.1928 +
  1.1929 +// Implicitly convert a size value to a jsval, ensuring that the size_t value
  1.1930 +// fits in a double.
  1.1931 +static bool
  1.1932 +SizeTojsval(JSContext* cx, size_t size, jsval* result)
  1.1933 +{
  1.1934 +  if (Convert<size_t>(double(size)) != size) {
  1.1935 +    JS_ReportError(cx, "size overflow");
  1.1936 +    return false;
  1.1937 +  }
  1.1938 +
  1.1939 +  *result = JS_NumberValue(double(size));
  1.1940 +  return true;
  1.1941 +}
  1.1942 +
  1.1943 +// Forcefully convert val to IntegerType when explicitly requested.
  1.1944 +template<class IntegerType>
  1.1945 +static bool
  1.1946 +jsvalToIntegerExplicit(jsval val, IntegerType* result)
  1.1947 +{
  1.1948 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.1949 +
  1.1950 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1951 +    // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
  1.1952 +    double d = JSVAL_TO_DOUBLE(val);
  1.1953 +    *result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
  1.1954 +    return true;
  1.1955 +  }
  1.1956 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.1957 +    // Convert Int64 and UInt64 values by C-style cast.
  1.1958 +    JSObject* obj = JSVAL_TO_OBJECT(val);
  1.1959 +    if (Int64::IsInt64(obj)) {
  1.1960 +      int64_t i = Int64Base::GetInt(obj);
  1.1961 +      *result = IntegerType(i);
  1.1962 +      return true;
  1.1963 +    }
  1.1964 +    if (UInt64::IsUInt64(obj)) {
  1.1965 +      uint64_t i = Int64Base::GetInt(obj);
  1.1966 +      *result = IntegerType(i);
  1.1967 +      return true;
  1.1968 +    }
  1.1969 +  }
  1.1970 +  return false;
  1.1971 +}
  1.1972 +
  1.1973 +// Forcefully convert val to a pointer value when explicitly requested.
  1.1974 +static bool
  1.1975 +jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
  1.1976 +{
  1.1977 +  if (JSVAL_IS_INT(val)) {
  1.1978 +    // int32_t always fits in intptr_t. If the integer is negative, cast through
  1.1979 +    // an intptr_t intermediate to sign-extend.
  1.1980 +    int32_t i = JSVAL_TO_INT(val);
  1.1981 +    *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
  1.1982 +    return true;
  1.1983 +  }
  1.1984 +  if (JSVAL_IS_DOUBLE(val)) {
  1.1985 +    double d = JSVAL_TO_DOUBLE(val);
  1.1986 +    if (d < 0) {
  1.1987 +      // Cast through an intptr_t intermediate to sign-extend.
  1.1988 +      intptr_t i = Convert<intptr_t>(d);
  1.1989 +      if (double(i) != d)
  1.1990 +        return false;
  1.1991 +
  1.1992 +      *result = uintptr_t(i);
  1.1993 +      return true;
  1.1994 +    }
  1.1995 +
  1.1996 +    // Don't silently lose bits here -- check that val really is an
  1.1997 +    // integer value, and has the right sign.
  1.1998 +    *result = Convert<uintptr_t>(d);
  1.1999 +    return double(*result) == d;
  1.2000 +  }
  1.2001 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.2002 +    JSObject* obj = JSVAL_TO_OBJECT(val);
  1.2003 +    if (Int64::IsInt64(obj)) {
  1.2004 +      int64_t i = Int64Base::GetInt(obj);
  1.2005 +      intptr_t p = intptr_t(i);
  1.2006 +
  1.2007 +      // Make sure the integer fits in the alotted precision.
  1.2008 +      if (int64_t(p) != i)
  1.2009 +        return false;
  1.2010 +      *result = uintptr_t(p);
  1.2011 +      return true;
  1.2012 +    }
  1.2013 +
  1.2014 +    if (UInt64::IsUInt64(obj)) {
  1.2015 +      uint64_t i = Int64Base::GetInt(obj);
  1.2016 +
  1.2017 +      // Make sure the integer fits in the alotted precision.
  1.2018 +      *result = uintptr_t(i);
  1.2019 +      return uint64_t(*result) == i;
  1.2020 +    }
  1.2021 +  }
  1.2022 +  return false;
  1.2023 +}
  1.2024 +
  1.2025 +template<class IntegerType, class CharType, size_t N, class AP>
  1.2026 +void
  1.2027 +IntegerToString(IntegerType i, int radix, Vector<CharType, N, AP>& result)
  1.2028 +{
  1.2029 +  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1.2030 +
  1.2031 +  // The buffer must be big enough for all the bits of IntegerType to fit,
  1.2032 +  // in base-2, including '-'.
  1.2033 +  CharType buffer[sizeof(IntegerType) * 8 + 1];
  1.2034 +  CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
  1.2035 +  CharType* cp = end;
  1.2036 +
  1.2037 +  // Build the string in reverse. We use multiplication and subtraction
  1.2038 +  // instead of modulus because that's much faster.
  1.2039 +  const bool isNegative = IsNegative(i);
  1.2040 +  size_t sign = isNegative ? -1 : 1;
  1.2041 +  do {
  1.2042 +    IntegerType ii = i / IntegerType(radix);
  1.2043 +    size_t index = sign * size_t(i - ii * IntegerType(radix));
  1.2044 +    *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[index];
  1.2045 +    i = ii;
  1.2046 +  } while (i != 0);
  1.2047 +
  1.2048 +  if (isNegative)
  1.2049 +    *--cp = '-';
  1.2050 +
  1.2051 +  JS_ASSERT(cp >= buffer);
  1.2052 +  result.append(cp, end);
  1.2053 +}
  1.2054 +
  1.2055 +template<class CharType>
  1.2056 +static size_t
  1.2057 +strnlen(const CharType* begin, size_t max)
  1.2058 +{
  1.2059 +  for (const CharType* s = begin; s != begin + max; ++s)
  1.2060 +    if (*s == 0)
  1.2061 +      return s - begin;
  1.2062 +
  1.2063 +  return max;
  1.2064 +}
  1.2065 +
  1.2066 +// Convert C binary value 'data' of CType 'typeObj' to a JS primitive, where
  1.2067 +// possible; otherwise, construct and return a CData object. The following
  1.2068 +// semantics apply when constructing a CData object for return:
  1.2069 +// * If 'wantPrimitive' is true, the caller indicates that 'result' must be
  1.2070 +//   a JS primitive, and ConvertToJS will fail if 'result' would be a CData
  1.2071 +//   object. Otherwise:
  1.2072 +// * If a CData object 'parentObj' is supplied, the new CData object is
  1.2073 +//   dependent on the given parent and its buffer refers to a slice of the
  1.2074 +//   parent's buffer.
  1.2075 +// * If 'parentObj' is null, the new CData object may or may not own its
  1.2076 +//   resulting buffer depending on the 'ownResult' argument.
  1.2077 +static bool
  1.2078 +ConvertToJS(JSContext* cx,
  1.2079 +            HandleObject typeObj,
  1.2080 +            HandleObject parentObj,
  1.2081 +            void* data,
  1.2082 +            bool wantPrimitive,
  1.2083 +            bool ownResult,
  1.2084 +            jsval* result)
  1.2085 +{
  1.2086 +  JS_ASSERT(!parentObj || CData::IsCData(parentObj));
  1.2087 +  JS_ASSERT(!parentObj || !ownResult);
  1.2088 +  JS_ASSERT(!wantPrimitive || !ownResult);
  1.2089 +
  1.2090 +  TypeCode typeCode = CType::GetTypeCode(typeObj);
  1.2091 +
  1.2092 +  switch (typeCode) {
  1.2093 +  case TYPE_void_t:
  1.2094 +    *result = JSVAL_VOID;
  1.2095 +    break;
  1.2096 +  case TYPE_bool:
  1.2097 +    *result = *static_cast<bool*>(data) ? JSVAL_TRUE : JSVAL_FALSE;
  1.2098 +    break;
  1.2099 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.2100 +  case TYPE_##name: {                                                          \
  1.2101 +    type value = *static_cast<type*>(data);                                    \
  1.2102 +    if (sizeof(type) < 4)                                                      \
  1.2103 +      *result = INT_TO_JSVAL(int32_t(value));                                  \
  1.2104 +    else                                                                       \
  1.2105 +      *result = JS_NumberValue(double(value));                                 \
  1.2106 +    break;                                                                     \
  1.2107 +  }
  1.2108 +#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
  1.2109 +  case TYPE_##name: {                                                          \
  1.2110 +    /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
  1.2111 +    uint64_t value;                                                            \
  1.2112 +    RootedObject proto(cx);                                                    \
  1.2113 +    if (!NumericLimits<type>::is_signed) {                                     \
  1.2114 +      value = *static_cast<type*>(data);                                       \
  1.2115 +      /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
  1.2116 +      proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
  1.2117 +      if (!proto)                                                              \
  1.2118 +        return false;                                                          \
  1.2119 +    } else {                                                                   \
  1.2120 +      value = int64_t(*static_cast<type*>(data));                              \
  1.2121 +      /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */            \
  1.2122 +      proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO);           \
  1.2123 +      if (!proto)                                                              \
  1.2124 +        return false;                                                          \
  1.2125 +    }                                                                          \
  1.2126 +                                                                               \
  1.2127 +    JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
  1.2128 +      !NumericLimits<type>::is_signed);                                        \
  1.2129 +    if (!obj)                                                                  \
  1.2130 +      return false;                                                            \
  1.2131 +    *result = OBJECT_TO_JSVAL(obj);                                            \
  1.2132 +    break;                                                                     \
  1.2133 +  }
  1.2134 +#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  1.2135 +  case TYPE_##name: {                                                          \
  1.2136 +    type value = *static_cast<type*>(data);                                    \
  1.2137 +    *result = JS_NumberValue(double(value));                                   \
  1.2138 +    break;                                                                     \
  1.2139 +  }
  1.2140 +#define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
  1.2141 +  case TYPE_##name:                                                            \
  1.2142 +    /* Convert to an integer. We have no idea what character encoding to */    \
  1.2143 +    /* use, if any. */                                                         \
  1.2144 +    *result = INT_TO_JSVAL(*static_cast<type*>(data));                         \
  1.2145 +    break;
  1.2146 +#include "ctypes/typedefs.h"
  1.2147 +  case TYPE_jschar: {
  1.2148 +    // Convert the jschar to a 1-character string.
  1.2149 +    JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
  1.2150 +    if (!str)
  1.2151 +      return false;
  1.2152 +
  1.2153 +    *result = STRING_TO_JSVAL(str);
  1.2154 +    break;
  1.2155 +  }
  1.2156 +  case TYPE_pointer:
  1.2157 +  case TYPE_array:
  1.2158 +  case TYPE_struct: {
  1.2159 +    // We're about to create a new CData object to return. If the caller doesn't
  1.2160 +    // want this, return early.
  1.2161 +    if (wantPrimitive) {
  1.2162 +      JS_ReportError(cx, "cannot convert to primitive value");
  1.2163 +      return false;
  1.2164 +    }
  1.2165 +
  1.2166 +    JSObject* obj = CData::Create(cx, typeObj, parentObj, data, ownResult);
  1.2167 +    if (!obj)
  1.2168 +      return false;
  1.2169 +
  1.2170 +    *result = OBJECT_TO_JSVAL(obj);
  1.2171 +    break;
  1.2172 +  }
  1.2173 +  case TYPE_function:
  1.2174 +    MOZ_ASSUME_UNREACHABLE("cannot return a FunctionType");
  1.2175 +  }
  1.2176 +
  1.2177 +  return true;
  1.2178 +}
  1.2179 +
  1.2180 +// Determine if the contents of a typed array can be converted without
  1.2181 +// ambiguity to a C type. Elements of a Int8Array are converted to
  1.2182 +// ctypes.int8_t, UInt8Array to ctypes.uint8_t, etc.
  1.2183 +bool CanConvertTypedArrayItemTo(JSObject *baseType, JSObject *valObj, JSContext *cx) {
  1.2184 +  TypeCode baseTypeCode = CType::GetTypeCode(baseType);
  1.2185 +  if (baseTypeCode == TYPE_void_t) {
  1.2186 +    return true;
  1.2187 +  }
  1.2188 +  TypeCode elementTypeCode;
  1.2189 +  switch (JS_GetArrayBufferViewType(valObj)) {
  1.2190 +  case ScalarTypeDescr::TYPE_INT8:
  1.2191 +    elementTypeCode = TYPE_int8_t;
  1.2192 +    break;
  1.2193 +  case ScalarTypeDescr::TYPE_UINT8:
  1.2194 +  case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
  1.2195 +    elementTypeCode = TYPE_uint8_t;
  1.2196 +    break;
  1.2197 +  case ScalarTypeDescr::TYPE_INT16:
  1.2198 +    elementTypeCode = TYPE_int16_t;
  1.2199 +    break;
  1.2200 +  case ScalarTypeDescr::TYPE_UINT16:
  1.2201 +    elementTypeCode = TYPE_uint16_t;
  1.2202 +    break;
  1.2203 +  case ScalarTypeDescr::TYPE_INT32:
  1.2204 +    elementTypeCode = TYPE_int32_t;
  1.2205 +    break;
  1.2206 +  case ScalarTypeDescr::TYPE_UINT32:
  1.2207 +    elementTypeCode = TYPE_uint32_t;
  1.2208 +    break;
  1.2209 +  case ScalarTypeDescr::TYPE_FLOAT32:
  1.2210 +    elementTypeCode = TYPE_float32_t;
  1.2211 +    break;
  1.2212 +  case ScalarTypeDescr::TYPE_FLOAT64:
  1.2213 +    elementTypeCode = TYPE_float64_t;
  1.2214 +    break;
  1.2215 +  default:
  1.2216 +    return false;
  1.2217 +  }
  1.2218 +  return elementTypeCode == baseTypeCode;
  1.2219 +}
  1.2220 +
  1.2221 +// Implicitly convert jsval 'val' to a C binary representation of CType
  1.2222 +// 'targetType', storing the result in 'buffer'. Adequate space must be
  1.2223 +// provided in 'buffer' by the caller. This function generally does minimal
  1.2224 +// coercion between types. There are two cases in which this function is used:
  1.2225 +// 1) The target buffer is internal to a CData object; we simply write data
  1.2226 +//    into it.
  1.2227 +// 2) We are converting an argument for an ffi call, in which case 'isArgument'
  1.2228 +//    will be true. This allows us to handle a special case: if necessary,
  1.2229 +//    we can autoconvert a JS string primitive to a pointer-to-character type.
  1.2230 +//    In this case, ownership of the allocated string is handed off to the
  1.2231 +//    caller; 'freePointer' will be set to indicate this.
  1.2232 +static bool
  1.2233 +ImplicitConvert(JSContext* cx,
  1.2234 +                HandleValue val,
  1.2235 +                JSObject* targetType_,
  1.2236 +                void* buffer,
  1.2237 +                bool isArgument,
  1.2238 +                bool* freePointer)
  1.2239 +{
  1.2240 +  RootedObject targetType(cx, targetType_);
  1.2241 +  JS_ASSERT(CType::IsSizeDefined(targetType));
  1.2242 +
  1.2243 +  // First, check if val is either a CData object or a CDataFinalizer
  1.2244 +  // of type targetType.
  1.2245 +  JSObject* sourceData = nullptr;
  1.2246 +  JSObject* sourceType = nullptr;
  1.2247 +  RootedObject valObj(cx, nullptr);
  1.2248 +  if (!JSVAL_IS_PRIMITIVE(val)) {
  1.2249 +    valObj = JSVAL_TO_OBJECT(val);
  1.2250 +    if (CData::IsCData(valObj)) {
  1.2251 +      sourceData = valObj;
  1.2252 +      sourceType = CData::GetCType(sourceData);
  1.2253 +
  1.2254 +      // If the types are equal, copy the buffer contained within the CData.
  1.2255 +      // (Note that the buffers may overlap partially or completely.)
  1.2256 +      if (CType::TypesEqual(sourceType, targetType)) {
  1.2257 +        size_t size = CType::GetSize(sourceType);
  1.2258 +        memmove(buffer, CData::GetData(sourceData), size);
  1.2259 +        return true;
  1.2260 +      }
  1.2261 +    } else if (CDataFinalizer::IsCDataFinalizer(valObj)) {
  1.2262 +      sourceData = valObj;
  1.2263 +      sourceType = CDataFinalizer::GetCType(cx, sourceData);
  1.2264 +
  1.2265 +      CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.2266 +        JS_GetPrivate(sourceData);
  1.2267 +
  1.2268 +      if (!p) {
  1.2269 +        // We have called |dispose| or |forget| already.
  1.2270 +        JS_ReportError(cx, "Attempting to convert an empty CDataFinalizer");
  1.2271 +        return false;
  1.2272 +      }
  1.2273 +
  1.2274 +      // If the types are equal, copy the buffer contained within the CData.
  1.2275 +      if (CType::TypesEqual(sourceType, targetType)) {
  1.2276 +        memmove(buffer, p->cargs, p->cargs_size);
  1.2277 +        return true;
  1.2278 +      }
  1.2279 +    }
  1.2280 +  }
  1.2281 +
  1.2282 +  TypeCode targetCode = CType::GetTypeCode(targetType);
  1.2283 +
  1.2284 +  switch (targetCode) {
  1.2285 +  case TYPE_bool: {
  1.2286 +    // Do not implicitly lose bits, but allow the values 0, 1, and -0.
  1.2287 +    // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
  1.2288 +    bool result;
  1.2289 +    if (!jsvalToBool(cx, val, &result))
  1.2290 +      return TypeError(cx, "boolean", val);
  1.2291 +    *static_cast<bool*>(buffer) = result;
  1.2292 +    break;
  1.2293 +  }
  1.2294 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.2295 +  case TYPE_##name: {                                                          \
  1.2296 +    /* Do not implicitly lose bits. */                                         \
  1.2297 +    type result;                                                               \
  1.2298 +    if (!jsvalToInteger(cx, val, &result))                                     \
  1.2299 +      return TypeError(cx, #name, val);                                        \
  1.2300 +    *static_cast<type*>(buffer) = result;                                      \
  1.2301 +    break;                                                                     \
  1.2302 +  }
  1.2303 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.2304 +#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  1.2305 +  case TYPE_##name: {                                                          \
  1.2306 +    type result;                                                               \
  1.2307 +    if (!jsvalToFloat(cx, val, &result))                                       \
  1.2308 +      return TypeError(cx, #name, val);                                        \
  1.2309 +    *static_cast<type*>(buffer) = result;                                      \
  1.2310 +    break;                                                                     \
  1.2311 +  }
  1.2312 +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.2313 +#define DEFINE_JSCHAR_TYPE(name, type, ffiType)                                \
  1.2314 +  case TYPE_##name: {                                                          \
  1.2315 +    /* Convert from a 1-character string, regardless of encoding, */           \
  1.2316 +    /* or from an integer, provided the result fits in 'type'. */              \
  1.2317 +    type result;                                                               \
  1.2318 +    if (JSVAL_IS_STRING(val)) {                                                \
  1.2319 +      JSString* str = JSVAL_TO_STRING(val);                                    \
  1.2320 +      if (str->length() != 1)                                                  \
  1.2321 +        return TypeError(cx, #name, val);                                      \
  1.2322 +      const jschar *chars = str->getChars(cx);                                 \
  1.2323 +      if (!chars)                                                              \
  1.2324 +        return false;                                                          \
  1.2325 +      result = chars[0];                                                       \
  1.2326 +    } else if (!jsvalToInteger(cx, val, &result)) {                            \
  1.2327 +      return TypeError(cx, #name, val);                                        \
  1.2328 +    }                                                                          \
  1.2329 +    *static_cast<type*>(buffer) = result;                                      \
  1.2330 +    break;                                                                     \
  1.2331 +  }
  1.2332 +#include "ctypes/typedefs.h"
  1.2333 +  case TYPE_pointer: {
  1.2334 +    if (JSVAL_IS_NULL(val)) {
  1.2335 +      // Convert to a null pointer.
  1.2336 +      *static_cast<void**>(buffer) = nullptr;
  1.2337 +      break;
  1.2338 +    }
  1.2339 +
  1.2340 +    JS::Rooted<JSObject*> baseType(cx, PointerType::GetBaseType(targetType));
  1.2341 +    if (sourceData) {
  1.2342 +      // First, determine if the targetType is ctypes.void_t.ptr.
  1.2343 +      TypeCode sourceCode = CType::GetTypeCode(sourceType);
  1.2344 +      void* sourceBuffer = CData::GetData(sourceData);
  1.2345 +      bool voidptrTarget = CType::GetTypeCode(baseType) == TYPE_void_t;
  1.2346 +
  1.2347 +      if (sourceCode == TYPE_pointer && voidptrTarget) {
  1.2348 +        // Autoconvert if targetType is ctypes.voidptr_t.
  1.2349 +        *static_cast<void**>(buffer) = *static_cast<void**>(sourceBuffer);
  1.2350 +        break;
  1.2351 +      }
  1.2352 +      if (sourceCode == TYPE_array) {
  1.2353 +        // Autoconvert an array to a ctypes.void_t.ptr or to
  1.2354 +        // sourceType.elementType.ptr, just like C.
  1.2355 +        JSObject* elementType = ArrayType::GetBaseType(sourceType);
  1.2356 +        if (voidptrTarget || CType::TypesEqual(baseType, elementType)) {
  1.2357 +          *static_cast<void**>(buffer) = sourceBuffer;
  1.2358 +          break;
  1.2359 +        }
  1.2360 +      }
  1.2361 +
  1.2362 +    } else if (isArgument && JSVAL_IS_STRING(val)) {
  1.2363 +      // Convert the string for the ffi call. This requires allocating space
  1.2364 +      // which the caller assumes ownership of.
  1.2365 +      // TODO: Extend this so we can safely convert strings at other times also.
  1.2366 +      JSString* sourceString = JSVAL_TO_STRING(val);
  1.2367 +      size_t sourceLength = sourceString->length();
  1.2368 +      const jschar* sourceChars = sourceString->getChars(cx);
  1.2369 +      if (!sourceChars)
  1.2370 +        return false;
  1.2371 +
  1.2372 +      switch (CType::GetTypeCode(baseType)) {
  1.2373 +      case TYPE_char:
  1.2374 +      case TYPE_signed_char:
  1.2375 +      case TYPE_unsigned_char: {
  1.2376 +        // Convert from UTF-16 to UTF-8.
  1.2377 +        size_t nbytes =
  1.2378 +          GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  1.2379 +        if (nbytes == (size_t) -1)
  1.2380 +          return false;
  1.2381 +
  1.2382 +        char** charBuffer = static_cast<char**>(buffer);
  1.2383 +        *charBuffer = cx->pod_malloc<char>(nbytes + 1);
  1.2384 +        if (!*charBuffer) {
  1.2385 +          JS_ReportAllocationOverflow(cx);
  1.2386 +          return false;
  1.2387 +        }
  1.2388 +
  1.2389 +        ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
  1.2390 +                    *charBuffer, &nbytes));
  1.2391 +        (*charBuffer)[nbytes] = 0;
  1.2392 +        *freePointer = true;
  1.2393 +        break;
  1.2394 +      }
  1.2395 +      case TYPE_jschar: {
  1.2396 +        // Copy the jschar string data. (We could provide direct access to the
  1.2397 +        // JSString's buffer, but this approach is safer if the caller happens
  1.2398 +        // to modify the string.)
  1.2399 +        jschar** jscharBuffer = static_cast<jschar**>(buffer);
  1.2400 +        *jscharBuffer = cx->pod_malloc<jschar>(sourceLength + 1);
  1.2401 +        if (!*jscharBuffer) {
  1.2402 +          JS_ReportAllocationOverflow(cx);
  1.2403 +          return false;
  1.2404 +        }
  1.2405 +
  1.2406 +        *freePointer = true;
  1.2407 +        memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
  1.2408 +        (*jscharBuffer)[sourceLength] = 0;
  1.2409 +        break;
  1.2410 +      }
  1.2411 +      default:
  1.2412 +        return TypeError(cx, "string pointer", val);
  1.2413 +      }
  1.2414 +      break;
  1.2415 +    } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayBufferObject(valObj)) {
  1.2416 +      // Convert ArrayBuffer to pointer without any copy.
  1.2417 +      // Just as with C arrays, we make no effort to
  1.2418 +      // keep the ArrayBuffer alive.
  1.2419 +      void* p = JS_GetStableArrayBufferData(cx, valObj);
  1.2420 +      if (!p)
  1.2421 +          return false;
  1.2422 +      *static_cast<void**>(buffer) = p;
  1.2423 +      break;
  1.2424 +    } if (!JSVAL_IS_PRIMITIVE(val) && JS_IsTypedArrayObject(valObj)) {
  1.2425 +      if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
  1.2426 +        return TypeError(cx, "typed array with the appropriate type", val);
  1.2427 +      }
  1.2428 +
  1.2429 +      // Convert TypedArray to pointer without any copy.
  1.2430 +      // Just as with C arrays, we make no effort to
  1.2431 +      // keep the TypedArray alive.
  1.2432 +      *static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
  1.2433 +      break;
  1.2434 +    }
  1.2435 +    return TypeError(cx, "pointer", val);
  1.2436 +  }
  1.2437 +  case TYPE_array: {
  1.2438 +    RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
  1.2439 +    size_t targetLength = ArrayType::GetLength(targetType);
  1.2440 +
  1.2441 +    if (JSVAL_IS_STRING(val)) {
  1.2442 +      JSString* sourceString = JSVAL_TO_STRING(val);
  1.2443 +      size_t sourceLength = sourceString->length();
  1.2444 +      const jschar* sourceChars = sourceString->getChars(cx);
  1.2445 +      if (!sourceChars)
  1.2446 +        return false;
  1.2447 +
  1.2448 +      switch (CType::GetTypeCode(baseType)) {
  1.2449 +      case TYPE_char:
  1.2450 +      case TYPE_signed_char:
  1.2451 +      case TYPE_unsigned_char: {
  1.2452 +        // Convert from UTF-16 to UTF-8.
  1.2453 +        size_t nbytes =
  1.2454 +          GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  1.2455 +        if (nbytes == (size_t) -1)
  1.2456 +          return false;
  1.2457 +
  1.2458 +        if (targetLength < nbytes) {
  1.2459 +          JS_ReportError(cx, "ArrayType has insufficient length");
  1.2460 +          return false;
  1.2461 +        }
  1.2462 +
  1.2463 +        char* charBuffer = static_cast<char*>(buffer);
  1.2464 +        ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
  1.2465 +                    charBuffer, &nbytes));
  1.2466 +
  1.2467 +        if (targetLength > nbytes)
  1.2468 +          charBuffer[nbytes] = 0;
  1.2469 +
  1.2470 +        break;
  1.2471 +      }
  1.2472 +      case TYPE_jschar: {
  1.2473 +        // Copy the string data, jschar for jschar, including the terminator
  1.2474 +        // if there's space.
  1.2475 +        if (targetLength < sourceLength) {
  1.2476 +          JS_ReportError(cx, "ArrayType has insufficient length");
  1.2477 +          return false;
  1.2478 +        }
  1.2479 +
  1.2480 +        memcpy(buffer, sourceChars, sourceLength * sizeof(jschar));
  1.2481 +        if (targetLength > sourceLength)
  1.2482 +          static_cast<jschar*>(buffer)[sourceLength] = 0;
  1.2483 +
  1.2484 +        break;
  1.2485 +      }
  1.2486 +      default:
  1.2487 +        return TypeError(cx, "array", val);
  1.2488 +      }
  1.2489 +
  1.2490 +    } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayObject(cx, valObj)) {
  1.2491 +      // Convert each element of the array by calling ImplicitConvert.
  1.2492 +      uint32_t sourceLength;
  1.2493 +      if (!JS_GetArrayLength(cx, valObj, &sourceLength) ||
  1.2494 +          targetLength != size_t(sourceLength)) {
  1.2495 +        JS_ReportError(cx, "ArrayType length does not match source array length");
  1.2496 +        return false;
  1.2497 +      }
  1.2498 +
  1.2499 +      // Convert into an intermediate, in case of failure.
  1.2500 +      size_t elementSize = CType::GetSize(baseType);
  1.2501 +      size_t arraySize = elementSize * targetLength;
  1.2502 +      AutoPtr<char> intermediate(cx->pod_malloc<char>(arraySize));
  1.2503 +      if (!intermediate) {
  1.2504 +        JS_ReportAllocationOverflow(cx);
  1.2505 +        return false;
  1.2506 +      }
  1.2507 +
  1.2508 +      for (uint32_t i = 0; i < sourceLength; ++i) {
  1.2509 +        RootedValue item(cx);
  1.2510 +        if (!JS_GetElement(cx, valObj, i, &item))
  1.2511 +          return false;
  1.2512 +
  1.2513 +        char* data = intermediate.get() + elementSize * i;
  1.2514 +        if (!ImplicitConvert(cx, item, baseType, data, false, nullptr))
  1.2515 +          return false;
  1.2516 +      }
  1.2517 +
  1.2518 +      memcpy(buffer, intermediate.get(), arraySize);
  1.2519 +
  1.2520 +    } else if (!JSVAL_IS_PRIMITIVE(val) &&
  1.2521 +               JS_IsArrayBufferObject(valObj)) {
  1.2522 +      // Check that array is consistent with type, then
  1.2523 +      // copy the array.
  1.2524 +      uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
  1.2525 +      size_t elementSize = CType::GetSize(baseType);
  1.2526 +      size_t arraySize = elementSize * targetLength;
  1.2527 +      if (arraySize != size_t(sourceLength)) {
  1.2528 +        JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
  1.2529 +        return false;
  1.2530 +      }
  1.2531 +      memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
  1.2532 +      break;
  1.2533 +    }  else if (!JSVAL_IS_PRIMITIVE(val) &&
  1.2534 +               JS_IsTypedArrayObject(valObj)) {
  1.2535 +      // Check that array is consistent with type, then
  1.2536 +      // copy the array.
  1.2537 +      if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
  1.2538 +        return TypeError(cx, "typed array with the appropriate type", val);
  1.2539 +      }
  1.2540 +
  1.2541 +      uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
  1.2542 +      size_t elementSize = CType::GetSize(baseType);
  1.2543 +      size_t arraySize = elementSize * targetLength;
  1.2544 +      if (arraySize != size_t(sourceLength)) {
  1.2545 +        JS_ReportError(cx, "typed array length does not match source TypedArray length");
  1.2546 +        return false;
  1.2547 +      }
  1.2548 +      memcpy(buffer, JS_GetArrayBufferViewData(valObj), sourceLength);
  1.2549 +      break;
  1.2550 +    } else {
  1.2551 +      // Don't implicitly convert to string. Users can implicitly convert
  1.2552 +      // with `String(x)` or `""+x`.
  1.2553 +      return TypeError(cx, "array", val);
  1.2554 +    }
  1.2555 +    break;
  1.2556 +  }
  1.2557 +  case TYPE_struct: {
  1.2558 +    if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) {
  1.2559 +      // Enumerate the properties of the object; if they match the struct
  1.2560 +      // specification, convert the fields.
  1.2561 +      RootedObject iter(cx, JS_NewPropertyIterator(cx, valObj));
  1.2562 +      if (!iter)
  1.2563 +        return false;
  1.2564 +
  1.2565 +      // Convert into an intermediate, in case of failure.
  1.2566 +      size_t structSize = CType::GetSize(targetType);
  1.2567 +      AutoPtr<char> intermediate(cx->pod_malloc<char>(structSize));
  1.2568 +      if (!intermediate) {
  1.2569 +        JS_ReportAllocationOverflow(cx);
  1.2570 +        return false;
  1.2571 +      }
  1.2572 +
  1.2573 +      RootedId id(cx);
  1.2574 +      size_t i = 0;
  1.2575 +      while (1) {
  1.2576 +        if (!JS_NextProperty(cx, iter, id.address()))
  1.2577 +          return false;
  1.2578 +        if (JSID_IS_VOID(id))
  1.2579 +          break;
  1.2580 +
  1.2581 +        if (!JSID_IS_STRING(id)) {
  1.2582 +          JS_ReportError(cx, "property name is not a string");
  1.2583 +          return false;
  1.2584 +        }
  1.2585 +
  1.2586 +        JSFlatString *name = JSID_TO_FLAT_STRING(id);
  1.2587 +        const FieldInfo* field = StructType::LookupField(cx, targetType, name);
  1.2588 +        if (!field)
  1.2589 +          return false;
  1.2590 +
  1.2591 +        RootedValue prop(cx);
  1.2592 +        if (!JS_GetPropertyById(cx, valObj, id, &prop))
  1.2593 +          return false;
  1.2594 +
  1.2595 +        // Convert the field via ImplicitConvert().
  1.2596 +        char* fieldData = intermediate.get() + field->mOffset;
  1.2597 +        if (!ImplicitConvert(cx, prop, field->mType, fieldData, false, nullptr))
  1.2598 +          return false;
  1.2599 +
  1.2600 +        ++i;
  1.2601 +      }
  1.2602 +
  1.2603 +      const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
  1.2604 +      if (i != fields->count()) {
  1.2605 +        JS_ReportError(cx, "missing fields");
  1.2606 +        return false;
  1.2607 +      }
  1.2608 +
  1.2609 +      memcpy(buffer, intermediate.get(), structSize);
  1.2610 +      break;
  1.2611 +    }
  1.2612 +
  1.2613 +    return TypeError(cx, "struct", val);
  1.2614 +  }
  1.2615 +  case TYPE_void_t:
  1.2616 +  case TYPE_function:
  1.2617 +    MOZ_ASSUME_UNREACHABLE("invalid type");
  1.2618 +  }
  1.2619 +
  1.2620 +  return true;
  1.2621 +}
  1.2622 +
  1.2623 +// Convert jsval 'val' to a C binary representation of CType 'targetType',
  1.2624 +// storing the result in 'buffer'. This function is more forceful than
  1.2625 +// ImplicitConvert.
  1.2626 +static bool
  1.2627 +ExplicitConvert(JSContext* cx, HandleValue val, HandleObject targetType, void* buffer)
  1.2628 +{
  1.2629 +  // If ImplicitConvert succeeds, use that result.
  1.2630 +  if (ImplicitConvert(cx, val, targetType, buffer, false, nullptr))
  1.2631 +    return true;
  1.2632 +
  1.2633 +  // If ImplicitConvert failed, and there is no pending exception, then assume
  1.2634 +  // hard failure (out of memory, or some other similarly serious condition).
  1.2635 +  // We store any pending exception in case we need to re-throw it.
  1.2636 +  RootedValue ex(cx);
  1.2637 +  if (!JS_GetPendingException(cx, &ex))
  1.2638 +    return false;
  1.2639 +
  1.2640 +  // Otherwise, assume soft failure. Clear the pending exception so that we
  1.2641 +  // can throw a different one as required.
  1.2642 +  JS_ClearPendingException(cx);
  1.2643 +
  1.2644 +  TypeCode type = CType::GetTypeCode(targetType);
  1.2645 +
  1.2646 +  switch (type) {
  1.2647 +  case TYPE_bool: {
  1.2648 +    *static_cast<bool*>(buffer) = ToBoolean(val);
  1.2649 +    break;
  1.2650 +  }
  1.2651 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.2652 +  case TYPE_##name: {                                                          \
  1.2653 +    /* Convert numeric values with a C-style cast, and */                      \
  1.2654 +    /* allow conversion from a base-10 or base-16 string. */                   \
  1.2655 +    type result;                                                               \
  1.2656 +    if (!jsvalToIntegerExplicit(val, &result) &&                               \
  1.2657 +        (!JSVAL_IS_STRING(val) ||                                              \
  1.2658 +         !StringToInteger(cx, JSVAL_TO_STRING(val), &result)))                 \
  1.2659 +      return TypeError(cx, #name, val);                                        \
  1.2660 +    *static_cast<type*>(buffer) = result;                                      \
  1.2661 +    break;                                                                     \
  1.2662 +  }
  1.2663 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.2664 +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.2665 +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z)
  1.2666 +#include "ctypes/typedefs.h"
  1.2667 +  case TYPE_pointer: {
  1.2668 +    // Convert a number, Int64 object, or UInt64 object to a pointer.
  1.2669 +    uintptr_t result;
  1.2670 +    if (!jsvalToPtrExplicit(cx, val, &result))
  1.2671 +      return TypeError(cx, "pointer", val);
  1.2672 +    *static_cast<uintptr_t*>(buffer) = result;
  1.2673 +    break;
  1.2674 +  }
  1.2675 +  case TYPE_float32_t:
  1.2676 +  case TYPE_float64_t:
  1.2677 +  case TYPE_float:
  1.2678 +  case TYPE_double:
  1.2679 +  case TYPE_array:
  1.2680 +  case TYPE_struct:
  1.2681 +    // ImplicitConvert is sufficient. Re-throw the exception it generated.
  1.2682 +    JS_SetPendingException(cx, ex);
  1.2683 +    return false;
  1.2684 +  case TYPE_void_t:
  1.2685 +  case TYPE_function:
  1.2686 +    MOZ_ASSUME_UNREACHABLE("invalid type");
  1.2687 +  }
  1.2688 +  return true;
  1.2689 +}
  1.2690 +
  1.2691 +// Given a CType 'typeObj', generate a string describing the C type declaration
  1.2692 +// corresponding to 'typeObj'. For instance, the CType constructed from
  1.2693 +// 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string
  1.2694 +// 'int32_t*(**)[4]'.
  1.2695 +static JSString*
  1.2696 +BuildTypeName(JSContext* cx, JSObject* typeObj_)
  1.2697 +{
  1.2698 +  AutoString result;
  1.2699 +  RootedObject typeObj(cx, typeObj_);
  1.2700 +
  1.2701 +  // Walk the hierarchy of types, outermost to innermost, building up the type
  1.2702 +  // string. This consists of the base type, which goes on the left.
  1.2703 +  // Derived type modifiers (* and []) build from the inside outward, with
  1.2704 +  // pointers on the left and arrays on the right. An excellent description
  1.2705 +  // of the rules for building C type declarations can be found at:
  1.2706 +  // http://unixwiz.net/techtips/reading-cdecl.html
  1.2707 +  TypeCode prevGrouping = CType::GetTypeCode(typeObj), currentGrouping;
  1.2708 +  while (1) {
  1.2709 +    currentGrouping = CType::GetTypeCode(typeObj);
  1.2710 +    switch (currentGrouping) {
  1.2711 +    case TYPE_pointer: {
  1.2712 +      // Pointer types go on the left.
  1.2713 +      PrependString(result, "*");
  1.2714 +
  1.2715 +      typeObj = PointerType::GetBaseType(typeObj);
  1.2716 +      prevGrouping = currentGrouping;
  1.2717 +      continue;
  1.2718 +    }
  1.2719 +    case TYPE_array: {
  1.2720 +      if (prevGrouping == TYPE_pointer) {
  1.2721 +        // Outer type is pointer, inner type is array. Grouping is required.
  1.2722 +        PrependString(result, "(");
  1.2723 +        AppendString(result, ")");
  1.2724 +      }
  1.2725 +
  1.2726 +      // Array types go on the right.
  1.2727 +      AppendString(result, "[");
  1.2728 +      size_t length;
  1.2729 +      if (ArrayType::GetSafeLength(typeObj, &length))
  1.2730 +        IntegerToString(length, 10, result);
  1.2731 +
  1.2732 +      AppendString(result, "]");
  1.2733 +
  1.2734 +      typeObj = ArrayType::GetBaseType(typeObj);
  1.2735 +      prevGrouping = currentGrouping;
  1.2736 +      continue;
  1.2737 +    }
  1.2738 +    case TYPE_function: {
  1.2739 +      FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  1.2740 +
  1.2741 +      // Add in the calling convention, if it's not cdecl.
  1.2742 +      // There's no trailing or leading space needed here, as none of the
  1.2743 +      // modifiers can produce a string beginning with an identifier ---
  1.2744 +      // except for TYPE_function itself, which is fine because functions
  1.2745 +      // can't return functions.
  1.2746 +      ABICode abi = GetABICode(fninfo->mABI);
  1.2747 +      if (abi == ABI_STDCALL)
  1.2748 +        PrependString(result, "__stdcall");
  1.2749 +      else if (abi == ABI_WINAPI)
  1.2750 +        PrependString(result, "WINAPI");
  1.2751 +
  1.2752 +      // Function application binds more tightly than dereferencing, so
  1.2753 +      // wrap pointer types in parens. Functions can't return functions
  1.2754 +      // (only pointers to them), and arrays can't hold functions
  1.2755 +      // (similarly), so we don't need to address those cases.
  1.2756 +      if (prevGrouping == TYPE_pointer) {
  1.2757 +        PrependString(result, "(");
  1.2758 +        AppendString(result, ")");
  1.2759 +      }
  1.2760 +
  1.2761 +      // Argument list goes on the right.
  1.2762 +      AppendString(result, "(");
  1.2763 +      for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  1.2764 +        RootedObject argType(cx, fninfo->mArgTypes[i]);
  1.2765 +        JSString* argName = CType::GetName(cx, argType);
  1.2766 +        AppendString(result, argName);
  1.2767 +        if (i != fninfo->mArgTypes.length() - 1 ||
  1.2768 +            fninfo->mIsVariadic)
  1.2769 +          AppendString(result, ", ");
  1.2770 +      }
  1.2771 +      if (fninfo->mIsVariadic)
  1.2772 +        AppendString(result, "...");
  1.2773 +      AppendString(result, ")");
  1.2774 +
  1.2775 +      // Set 'typeObj' to the return type, and let the loop process it.
  1.2776 +      // 'prevGrouping' doesn't matter here, because functions cannot return
  1.2777 +      // arrays -- thus the parenthetical rules don't get tickled.
  1.2778 +      typeObj = fninfo->mReturnType;
  1.2779 +      continue;
  1.2780 +    }
  1.2781 +    default:
  1.2782 +      // Either a basic or struct type. Use the type's name as the base type.
  1.2783 +      break;
  1.2784 +    }
  1.2785 +    break;
  1.2786 +  }
  1.2787 +
  1.2788 +  // If prepending the base type name directly would splice two
  1.2789 +  // identifiers, insert a space.
  1.2790 +  if (('a' <= result[0] && result[0] <= 'z') ||
  1.2791 +      ('A' <= result[0] && result[0] <= 'Z') ||
  1.2792 +      (result[0] == '_'))
  1.2793 +    PrependString(result, " ");
  1.2794 +
  1.2795 +  // Stick the base type and derived type parts together.
  1.2796 +  JSString* baseName = CType::GetName(cx, typeObj);
  1.2797 +  PrependString(result, baseName);
  1.2798 +  return NewUCString(cx, result);
  1.2799 +}
  1.2800 +
  1.2801 +// Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
  1.2802 +// would construct the same CType. If 'makeShort' is true, assume that any
  1.2803 +// StructType 't' is bound to an in-scope variable of name 't.name', and use
  1.2804 +// that variable in place of generating a string to construct the type 't'.
  1.2805 +// (This means the type comparison function CType::TypesEqual will return true
  1.2806 +// when comparing the input and output of BuildTypeSource, since struct
  1.2807 +// equality is determined by strict JSObject pointer equality.)
  1.2808 +static void
  1.2809 +BuildTypeSource(JSContext* cx,
  1.2810 +                JSObject* typeObj_,
  1.2811 +                bool makeShort,
  1.2812 +                AutoString& result)
  1.2813 +{
  1.2814 +  RootedObject typeObj(cx, typeObj_);
  1.2815 +
  1.2816 +  // Walk the types, building up the toSource() string.
  1.2817 +  switch (CType::GetTypeCode(typeObj)) {
  1.2818 +  case TYPE_void_t:
  1.2819 +#define DEFINE_TYPE(name, type, ffiType)  \
  1.2820 +  case TYPE_##name:
  1.2821 +#include "ctypes/typedefs.h"
  1.2822 +  {
  1.2823 +    AppendString(result, "ctypes.");
  1.2824 +    JSString* nameStr = CType::GetName(cx, typeObj);
  1.2825 +    AppendString(result, nameStr);
  1.2826 +    break;
  1.2827 +  }
  1.2828 +  case TYPE_pointer: {
  1.2829 +    RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
  1.2830 +
  1.2831 +    // Specialcase ctypes.voidptr_t.
  1.2832 +    if (CType::GetTypeCode(baseType) == TYPE_void_t) {
  1.2833 +      AppendString(result, "ctypes.voidptr_t");
  1.2834 +      break;
  1.2835 +    }
  1.2836 +
  1.2837 +    // Recursively build the source string, and append '.ptr'.
  1.2838 +    BuildTypeSource(cx, baseType, makeShort, result);
  1.2839 +    AppendString(result, ".ptr");
  1.2840 +    break;
  1.2841 +  }
  1.2842 +  case TYPE_function: {
  1.2843 +    FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  1.2844 +
  1.2845 +    AppendString(result, "ctypes.FunctionType(");
  1.2846 +
  1.2847 +    switch (GetABICode(fninfo->mABI)) {
  1.2848 +    case ABI_DEFAULT:
  1.2849 +      AppendString(result, "ctypes.default_abi, ");
  1.2850 +      break;
  1.2851 +    case ABI_STDCALL:
  1.2852 +      AppendString(result, "ctypes.stdcall_abi, ");
  1.2853 +      break;
  1.2854 +    case ABI_WINAPI:
  1.2855 +      AppendString(result, "ctypes.winapi_abi, ");
  1.2856 +      break;
  1.2857 +    case INVALID_ABI:
  1.2858 +      MOZ_ASSUME_UNREACHABLE("invalid abi");
  1.2859 +    }
  1.2860 +
  1.2861 +    // Recursively build the source string describing the function return and
  1.2862 +    // argument types.
  1.2863 +    BuildTypeSource(cx, fninfo->mReturnType, true, result);
  1.2864 +
  1.2865 +    if (fninfo->mArgTypes.length() > 0) {
  1.2866 +      AppendString(result, ", [");
  1.2867 +      for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  1.2868 +        BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
  1.2869 +        if (i != fninfo->mArgTypes.length() - 1 ||
  1.2870 +            fninfo->mIsVariadic)
  1.2871 +          AppendString(result, ", ");
  1.2872 +      }
  1.2873 +      if (fninfo->mIsVariadic)
  1.2874 +        AppendString(result, "\"...\"");
  1.2875 +      AppendString(result, "]");
  1.2876 +    }
  1.2877 +
  1.2878 +    AppendString(result, ")");
  1.2879 +    break;
  1.2880 +  }
  1.2881 +  case TYPE_array: {
  1.2882 +    // Recursively build the source string, and append '.array(n)',
  1.2883 +    // where n is the array length, or the empty string if the array length
  1.2884 +    // is undefined.
  1.2885 +    JSObject* baseType = ArrayType::GetBaseType(typeObj);
  1.2886 +    BuildTypeSource(cx, baseType, makeShort, result);
  1.2887 +    AppendString(result, ".array(");
  1.2888 +
  1.2889 +    size_t length;
  1.2890 +    if (ArrayType::GetSafeLength(typeObj, &length))
  1.2891 +      IntegerToString(length, 10, result);
  1.2892 +
  1.2893 +    AppendString(result, ")");
  1.2894 +    break;
  1.2895 +  }
  1.2896 +  case TYPE_struct: {
  1.2897 +    JSString* name = CType::GetName(cx, typeObj);
  1.2898 +
  1.2899 +    if (makeShort) {
  1.2900 +      // Shorten the type declaration by assuming that StructType 't' is bound
  1.2901 +      // to an in-scope variable of name 't.name'.
  1.2902 +      AppendString(result, name);
  1.2903 +      break;
  1.2904 +    }
  1.2905 +
  1.2906 +    // Write the full struct declaration.
  1.2907 +    AppendString(result, "ctypes.StructType(\"");
  1.2908 +    AppendString(result, name);
  1.2909 +    AppendString(result, "\"");
  1.2910 +
  1.2911 +    // If it's an opaque struct, we're done.
  1.2912 +    if (!CType::IsSizeDefined(typeObj)) {
  1.2913 +      AppendString(result, ")");
  1.2914 +      break;
  1.2915 +    }
  1.2916 +
  1.2917 +    AppendString(result, ", [");
  1.2918 +
  1.2919 +    const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
  1.2920 +    size_t length = fields->count();
  1.2921 +    Array<const FieldInfoHash::Entry*, 64> fieldsArray;
  1.2922 +    if (!fieldsArray.resize(length))
  1.2923 +      break;
  1.2924 +
  1.2925 +    for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
  1.2926 +      fieldsArray[r.front().value().mIndex] = &r.front();
  1.2927 +
  1.2928 +    for (size_t i = 0; i < length; ++i) {
  1.2929 +      const FieldInfoHash::Entry* entry = fieldsArray[i];
  1.2930 +      AppendString(result, "{ \"");
  1.2931 +      AppendString(result, entry->key());
  1.2932 +      AppendString(result, "\": ");
  1.2933 +      BuildTypeSource(cx, entry->value().mType, true, result);
  1.2934 +      AppendString(result, " }");
  1.2935 +      if (i != length - 1)
  1.2936 +        AppendString(result, ", ");
  1.2937 +    }
  1.2938 +
  1.2939 +    AppendString(result, "])");
  1.2940 +    break;
  1.2941 +  }
  1.2942 +  }
  1.2943 +}
  1.2944 +
  1.2945 +// Given a CData object of CType 'typeObj' with binary value 'data', generate a
  1.2946 +// string 'result' such that 'eval(result)' would construct a CData object with
  1.2947 +// the same CType and containing the same binary value. This assumes that any
  1.2948 +// StructType 't' is bound to an in-scope variable of name 't.name'. (This means
  1.2949 +// the type comparison function CType::TypesEqual will return true when
  1.2950 +// comparing the types, since struct equality is determined by strict JSObject
  1.2951 +// pointer equality.) Further, if 'isImplicit' is true, ensure that the
  1.2952 +// resulting string can ImplicitConvert successfully if passed to another data
  1.2953 +// constructor. (This is important when called recursively, since fields of
  1.2954 +// structs and arrays are converted with ImplicitConvert.)
  1.2955 +static bool
  1.2956 +BuildDataSource(JSContext* cx,
  1.2957 +                HandleObject typeObj,
  1.2958 +                void* data,
  1.2959 +                bool isImplicit,
  1.2960 +                AutoString& result)
  1.2961 +{
  1.2962 +  TypeCode type = CType::GetTypeCode(typeObj);
  1.2963 +  switch (type) {
  1.2964 +  case TYPE_bool:
  1.2965 +    if (*static_cast<bool*>(data))
  1.2966 +      AppendString(result, "true");
  1.2967 +    else
  1.2968 +      AppendString(result, "false");
  1.2969 +    break;
  1.2970 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.2971 +  case TYPE_##name:                                                            \
  1.2972 +    /* Serialize as a primitive decimal integer. */                            \
  1.2973 +    IntegerToString(*static_cast<type*>(data), 10, result);                    \
  1.2974 +    break;
  1.2975 +#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
  1.2976 +  case TYPE_##name:                                                            \
  1.2977 +    /* Serialize as a wrapped decimal integer. */                              \
  1.2978 +    if (!NumericLimits<type>::is_signed)                                       \
  1.2979 +      AppendString(result, "ctypes.UInt64(\"");                                \
  1.2980 +    else                                                                       \
  1.2981 +      AppendString(result, "ctypes.Int64(\"");                                 \
  1.2982 +                                                                               \
  1.2983 +    IntegerToString(*static_cast<type*>(data), 10, result);                    \
  1.2984 +    AppendString(result, "\")");                                               \
  1.2985 +    break;
  1.2986 +#define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  1.2987 +  case TYPE_##name: {                                                          \
  1.2988 +    /* Serialize as a primitive double. */                                     \
  1.2989 +    double fp = *static_cast<type*>(data);                                     \
  1.2990 +    ToCStringBuf cbuf;                                                         \
  1.2991 +    char* str = NumberToCString(cx, &cbuf, fp);                                \
  1.2992 +    if (!str) {                                                                \
  1.2993 +      JS_ReportOutOfMemory(cx);                                                \
  1.2994 +      return false;                                                            \
  1.2995 +    }                                                                          \
  1.2996 +                                                                               \
  1.2997 +    result.append(str, strlen(str));                                           \
  1.2998 +    break;                                                                     \
  1.2999 +  }
  1.3000 +#define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
  1.3001 +  case TYPE_##name:                                                            \
  1.3002 +    /* Serialize as an integer. */                                             \
  1.3003 +    IntegerToString(*static_cast<type*>(data), 10, result);                    \
  1.3004 +    break;
  1.3005 +#include "ctypes/typedefs.h"
  1.3006 +  case TYPE_jschar: {
  1.3007 +    // Serialize as a 1-character JS string.
  1.3008 +    JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
  1.3009 +    if (!str)
  1.3010 +      return false;
  1.3011 +
  1.3012 +    // Escape characters, and quote as necessary.
  1.3013 +    RootedValue valStr(cx, StringValue(str));
  1.3014 +    JSString* src = JS_ValueToSource(cx, valStr);
  1.3015 +    if (!src)
  1.3016 +      return false;
  1.3017 +
  1.3018 +    AppendString(result, src);
  1.3019 +    break;
  1.3020 +  }
  1.3021 +  case TYPE_pointer:
  1.3022 +  case TYPE_function: {
  1.3023 +    if (isImplicit) {
  1.3024 +      // The result must be able to ImplicitConvert successfully.
  1.3025 +      // Wrap in a type constructor, then serialize for ExplicitConvert.
  1.3026 +      BuildTypeSource(cx, typeObj, true, result);
  1.3027 +      AppendString(result, "(");
  1.3028 +    }
  1.3029 +
  1.3030 +    // Serialize the pointer value as a wrapped hexadecimal integer.
  1.3031 +    uintptr_t ptr = *static_cast<uintptr_t*>(data);
  1.3032 +    AppendString(result, "ctypes.UInt64(\"0x");
  1.3033 +    IntegerToString(ptr, 16, result);
  1.3034 +    AppendString(result, "\")");
  1.3035 +
  1.3036 +    if (isImplicit)
  1.3037 +      AppendString(result, ")");
  1.3038 +
  1.3039 +    break;
  1.3040 +  }
  1.3041 +  case TYPE_array: {
  1.3042 +    // Serialize each element of the array recursively. Each element must
  1.3043 +    // be able to ImplicitConvert successfully.
  1.3044 +    RootedObject baseType(cx, ArrayType::GetBaseType(typeObj));
  1.3045 +    AppendString(result, "[");
  1.3046 +
  1.3047 +    size_t length = ArrayType::GetLength(typeObj);
  1.3048 +    size_t elementSize = CType::GetSize(baseType);
  1.3049 +    for (size_t i = 0; i < length; ++i) {
  1.3050 +      char* element = static_cast<char*>(data) + elementSize * i;
  1.3051 +      if (!BuildDataSource(cx, baseType, element, true, result))
  1.3052 +        return false;
  1.3053 +
  1.3054 +      if (i + 1 < length)
  1.3055 +        AppendString(result, ", ");
  1.3056 +    }
  1.3057 +    AppendString(result, "]");
  1.3058 +    break;
  1.3059 +  }
  1.3060 +  case TYPE_struct: {
  1.3061 +    if (isImplicit) {
  1.3062 +      // The result must be able to ImplicitConvert successfully.
  1.3063 +      // Serialize the data as an object with properties, rather than
  1.3064 +      // a sequence of arguments to the StructType constructor.
  1.3065 +      AppendString(result, "{");
  1.3066 +    }
  1.3067 +
  1.3068 +    // Serialize each field of the struct recursively. Each field must
  1.3069 +    // be able to ImplicitConvert successfully.
  1.3070 +    const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
  1.3071 +    size_t length = fields->count();
  1.3072 +    Array<const FieldInfoHash::Entry*, 64> fieldsArray;
  1.3073 +    if (!fieldsArray.resize(length))
  1.3074 +      return false;
  1.3075 +
  1.3076 +    for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
  1.3077 +      fieldsArray[r.front().value().mIndex] = &r.front();
  1.3078 +
  1.3079 +    for (size_t i = 0; i < length; ++i) {
  1.3080 +      const FieldInfoHash::Entry* entry = fieldsArray[i];
  1.3081 +
  1.3082 +      if (isImplicit) {
  1.3083 +        AppendString(result, "\"");
  1.3084 +        AppendString(result, entry->key());
  1.3085 +        AppendString(result, "\": ");
  1.3086 +      }
  1.3087 +
  1.3088 +      char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
  1.3089 +      RootedObject entryType(cx, entry->value().mType);
  1.3090 +      if (!BuildDataSource(cx, entryType, fieldData, true, result))
  1.3091 +        return false;
  1.3092 +
  1.3093 +      if (i + 1 != length)
  1.3094 +        AppendString(result, ", ");
  1.3095 +    }
  1.3096 +
  1.3097 +    if (isImplicit)
  1.3098 +      AppendString(result, "}");
  1.3099 +
  1.3100 +    break;
  1.3101 +  }
  1.3102 +  case TYPE_void_t:
  1.3103 +    MOZ_ASSUME_UNREACHABLE("invalid type");
  1.3104 +  }
  1.3105 +
  1.3106 +  return true;
  1.3107 +}
  1.3108 +
  1.3109 +/*******************************************************************************
  1.3110 +** JSAPI callback function implementations
  1.3111 +*******************************************************************************/
  1.3112 +
  1.3113 +bool
  1.3114 +ConstructAbstract(JSContext* cx,
  1.3115 +                  unsigned argc,
  1.3116 +                  jsval* vp)
  1.3117 +{
  1.3118 +  // Calling an abstract base class constructor is disallowed.
  1.3119 +  JS_ReportError(cx, "cannot construct from abstract type");
  1.3120 +  return false;
  1.3121 +}
  1.3122 +
  1.3123 +/*******************************************************************************
  1.3124 +** CType implementation
  1.3125 +*******************************************************************************/
  1.3126 +
  1.3127 +bool
  1.3128 +CType::ConstructData(JSContext* cx,
  1.3129 +                     unsigned argc,
  1.3130 +                     jsval* vp)
  1.3131 +{
  1.3132 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3133 +  // get the callee object...
  1.3134 +  RootedObject obj(cx, &args.callee());
  1.3135 +  if (!CType::IsCType(obj)) {
  1.3136 +    JS_ReportError(cx, "not a CType");
  1.3137 +    return false;
  1.3138 +  }
  1.3139 +
  1.3140 +  // How we construct the CData object depends on what type we represent.
  1.3141 +  // An instance 'd' of a CData object of type 't' has:
  1.3142 +  //   * [[Class]] "CData"
  1.3143 +  //   * __proto__ === t.prototype
  1.3144 +  switch (GetTypeCode(obj)) {
  1.3145 +  case TYPE_void_t:
  1.3146 +    JS_ReportError(cx, "cannot construct from void_t");
  1.3147 +    return false;
  1.3148 +  case TYPE_function:
  1.3149 +    JS_ReportError(cx, "cannot construct from FunctionType; use FunctionType.ptr instead");
  1.3150 +    return false;
  1.3151 +  case TYPE_pointer:
  1.3152 +    return PointerType::ConstructData(cx, obj, args);
  1.3153 +  case TYPE_array:
  1.3154 +    return ArrayType::ConstructData(cx, obj, args);
  1.3155 +  case TYPE_struct:
  1.3156 +    return StructType::ConstructData(cx, obj, args);
  1.3157 +  default:
  1.3158 +    return ConstructBasic(cx, obj, args);
  1.3159 +  }
  1.3160 +}
  1.3161 +
  1.3162 +bool
  1.3163 +CType::ConstructBasic(JSContext* cx,
  1.3164 +                      HandleObject obj,
  1.3165 +                      const CallArgs& args)
  1.3166 +{
  1.3167 +  if (args.length() > 1) {
  1.3168 +    JS_ReportError(cx, "CType constructor takes zero or one argument");
  1.3169 +    return false;
  1.3170 +  }
  1.3171 +
  1.3172 +  // construct a CData object
  1.3173 +  RootedObject result(cx, CData::Create(cx, obj, NullPtr(), nullptr, true));
  1.3174 +  if (!result)
  1.3175 +    return false;
  1.3176 +
  1.3177 +  if (args.length() == 1) {
  1.3178 +    if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result)))
  1.3179 +      return false;
  1.3180 +  }
  1.3181 +
  1.3182 +  args.rval().setObject(*result);
  1.3183 +  return true;
  1.3184 +}
  1.3185 +
  1.3186 +JSObject*
  1.3187 +CType::Create(JSContext* cx,
  1.3188 +              HandleObject typeProto,
  1.3189 +              HandleObject dataProto,
  1.3190 +              TypeCode type,
  1.3191 +              JSString* name_,
  1.3192 +              jsval size_,
  1.3193 +              jsval align_,
  1.3194 +              ffi_type* ffiType)
  1.3195 +{
  1.3196 +  RootedString name(cx, name_);
  1.3197 +  RootedValue size(cx, size_);
  1.3198 +  RootedValue align(cx, align_);
  1.3199 +  RootedObject parent(cx, JS_GetParent(typeProto));
  1.3200 +  JS_ASSERT(parent);
  1.3201 +
  1.3202 +  // Create a CType object with the properties and slots common to all CTypes.
  1.3203 +  // Each type object 't' has:
  1.3204 +  //   * [[Class]] "CType"
  1.3205 +  //   * __proto__ === 'typeProto'; one of ctypes.{CType,PointerType,ArrayType,
  1.3206 +  //     StructType}.prototype
  1.3207 +  //   * A constructor which creates and returns a CData object, containing
  1.3208 +  //     binary data of the given type.
  1.3209 +  //   * 'prototype' property:
  1.3210 +  //     * [[Class]] "CDataProto"
  1.3211 +  //     * __proto__ === 'dataProto'; an object containing properties and
  1.3212 +  //       functions common to all CData objects of types derived from
  1.3213 +  //       'typeProto'. (For instance, this could be ctypes.CData.prototype
  1.3214 +  //       for simple types, or something representing structs for StructTypes.)
  1.3215 +  //     * 'constructor' property === 't'
  1.3216 +  //     * Additional properties specified by 'ps', as appropriate for the
  1.3217 +  //       specific type instance 't'.
  1.3218 +  RootedObject typeObj(cx, JS_NewObject(cx, &sCTypeClass, typeProto, parent));
  1.3219 +  if (!typeObj)
  1.3220 +    return nullptr;
  1.3221 +
  1.3222 +  // Set up the reserved slots.
  1.3223 +  JS_SetReservedSlot(typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type));
  1.3224 +  if (ffiType)
  1.3225 +    JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType));
  1.3226 +  if (name)
  1.3227 +    JS_SetReservedSlot(typeObj, SLOT_NAME, STRING_TO_JSVAL(name));
  1.3228 +  JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
  1.3229 +  JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
  1.3230 +
  1.3231 +  if (dataProto) {
  1.3232 +    // Set up the 'prototype' and 'prototype.constructor' properties.
  1.3233 +    RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, parent));
  1.3234 +    if (!prototype)
  1.3235 +      return nullptr;
  1.3236 +
  1.3237 +    if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
  1.3238 +                           JSPROP_READONLY | JSPROP_PERMANENT))
  1.3239 +      return nullptr;
  1.3240 +
  1.3241 +    // Set the 'prototype' object.
  1.3242 +    //if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
  1.3243 +    //  return nullptr;
  1.3244 +    JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
  1.3245 +  }
  1.3246 +
  1.3247 +  if (!JS_FreezeObject(cx, typeObj))
  1.3248 +    return nullptr;
  1.3249 +
  1.3250 +  // Assert a sanity check on size and alignment: size % alignment should always
  1.3251 +  // be zero.
  1.3252 +  JS_ASSERT_IF(IsSizeDefined(typeObj),
  1.3253 +               GetSize(typeObj) % GetAlignment(typeObj) == 0);
  1.3254 +
  1.3255 +  return typeObj;
  1.3256 +}
  1.3257 +
  1.3258 +JSObject*
  1.3259 +CType::DefineBuiltin(JSContext* cx,
  1.3260 +                     JSObject* parent_,
  1.3261 +                     const char* propName,
  1.3262 +                     JSObject* typeProto_,
  1.3263 +                     JSObject* dataProto_,
  1.3264 +                     const char* name,
  1.3265 +                     TypeCode type,
  1.3266 +                     jsval size_,
  1.3267 +                     jsval align_,
  1.3268 +                     ffi_type* ffiType)
  1.3269 +{
  1.3270 +  RootedObject parent(cx, parent_);
  1.3271 +  RootedObject typeProto(cx, typeProto_);
  1.3272 +  RootedObject dataProto(cx, dataProto_);
  1.3273 +  RootedValue size(cx, size_);
  1.3274 +  RootedValue align(cx, align_);
  1.3275 +
  1.3276 +  RootedString nameStr(cx, JS_NewStringCopyZ(cx, name));
  1.3277 +  if (!nameStr)
  1.3278 +    return nullptr;
  1.3279 +
  1.3280 +  // Create a new CType object with the common properties and slots.
  1.3281 +  RootedObject typeObj(cx, Create(cx, typeProto, dataProto, type, nameStr, size, align, ffiType));
  1.3282 +  if (!typeObj)
  1.3283 +    return nullptr;
  1.3284 +
  1.3285 +  // Define the CType as a 'propName' property on 'parent'.
  1.3286 +  if (!JS_DefineProperty(cx, parent, propName, typeObj,
  1.3287 +                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.3288 +    return nullptr;
  1.3289 +
  1.3290 +  return typeObj;
  1.3291 +}
  1.3292 +
  1.3293 +void
  1.3294 +CType::Finalize(JSFreeOp *fop, JSObject* obj)
  1.3295 +{
  1.3296 +  // Make sure our TypeCode slot is legit. If it's not, bail.
  1.3297 +  jsval slot = JS_GetReservedSlot(obj, SLOT_TYPECODE);
  1.3298 +  if (JSVAL_IS_VOID(slot))
  1.3299 +    return;
  1.3300 +
  1.3301 +  // The contents of our slots depends on what kind of type we are.
  1.3302 +  switch (TypeCode(JSVAL_TO_INT(slot))) {
  1.3303 +  case TYPE_function: {
  1.3304 +    // Free the FunctionInfo.
  1.3305 +    slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
  1.3306 +    if (!JSVAL_IS_VOID(slot))
  1.3307 +      FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
  1.3308 +    break;
  1.3309 +  }
  1.3310 +
  1.3311 +  case TYPE_struct: {
  1.3312 +    // Free the FieldInfoHash table.
  1.3313 +    slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
  1.3314 +    if (!JSVAL_IS_VOID(slot)) {
  1.3315 +      void* info = JSVAL_TO_PRIVATE(slot);
  1.3316 +      FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
  1.3317 +    }
  1.3318 +  }
  1.3319 +
  1.3320 +    // Fall through.
  1.3321 +  case TYPE_array: {
  1.3322 +    // Free the ffi_type info.
  1.3323 +    slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
  1.3324 +    if (!JSVAL_IS_VOID(slot)) {
  1.3325 +      ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
  1.3326 +      FreeOp::get(fop)->free_(ffiType->elements);
  1.3327 +      FreeOp::get(fop)->delete_(ffiType);
  1.3328 +    }
  1.3329 +
  1.3330 +    break;
  1.3331 +  }
  1.3332 +  default:
  1.3333 +    // Nothing to do here.
  1.3334 +    break;
  1.3335 +  }
  1.3336 +}
  1.3337 +
  1.3338 +void
  1.3339 +CType::Trace(JSTracer* trc, JSObject* obj)
  1.3340 +{
  1.3341 +  // Make sure our TypeCode slot is legit. If it's not, bail.
  1.3342 +  jsval slot = obj->getSlot(SLOT_TYPECODE);
  1.3343 +  if (JSVAL_IS_VOID(slot))
  1.3344 +    return;
  1.3345 +
  1.3346 +  // The contents of our slots depends on what kind of type we are.
  1.3347 +  switch (TypeCode(JSVAL_TO_INT(slot))) {
  1.3348 +  case TYPE_struct: {
  1.3349 +    slot = obj->getReservedSlot(SLOT_FIELDINFO);
  1.3350 +    if (JSVAL_IS_VOID(slot))
  1.3351 +      return;
  1.3352 +
  1.3353 +    FieldInfoHash* fields =
  1.3354 +      static_cast<FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
  1.3355 +    for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
  1.3356 +      JSString *key = e.front().key();
  1.3357 +      JS_CallStringTracer(trc, &key, "fieldName");
  1.3358 +      if (key != e.front().key())
  1.3359 +          e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
  1.3360 +      JS_CallHeapObjectTracer(trc, &e.front().value().mType, "fieldType");
  1.3361 +    }
  1.3362 +
  1.3363 +    break;
  1.3364 +  }
  1.3365 +  case TYPE_function: {
  1.3366 +    // Check if we have a FunctionInfo.
  1.3367 +    slot = obj->getReservedSlot(SLOT_FNINFO);
  1.3368 +    if (JSVAL_IS_VOID(slot))
  1.3369 +      return;
  1.3370 +
  1.3371 +    FunctionInfo* fninfo = static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
  1.3372 +    JS_ASSERT(fninfo);
  1.3373 +
  1.3374 +    // Identify our objects to the tracer.
  1.3375 +    JS_CallHeapObjectTracer(trc, &fninfo->mABI, "abi");
  1.3376 +    JS_CallHeapObjectTracer(trc, &fninfo->mReturnType, "returnType");
  1.3377 +    for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i)
  1.3378 +      JS_CallHeapObjectTracer(trc, &fninfo->mArgTypes[i], "argType");
  1.3379 +
  1.3380 +    break;
  1.3381 +  }
  1.3382 +  default:
  1.3383 +    // Nothing to do here.
  1.3384 +    break;
  1.3385 +  }
  1.3386 +}
  1.3387 +
  1.3388 +bool
  1.3389 +CType::IsCType(JSObject* obj)
  1.3390 +{
  1.3391 +  return JS_GetClass(obj) == &sCTypeClass;
  1.3392 +}
  1.3393 +
  1.3394 +bool
  1.3395 +CType::IsCTypeProto(JSObject* obj)
  1.3396 +{
  1.3397 +  return JS_GetClass(obj) == &sCTypeProtoClass;
  1.3398 +}
  1.3399 +
  1.3400 +TypeCode
  1.3401 +CType::GetTypeCode(JSObject* typeObj)
  1.3402 +{
  1.3403 +  JS_ASSERT(IsCType(typeObj));
  1.3404 +
  1.3405 +  jsval result = JS_GetReservedSlot(typeObj, SLOT_TYPECODE);
  1.3406 +  return TypeCode(JSVAL_TO_INT(result));
  1.3407 +}
  1.3408 +
  1.3409 +bool
  1.3410 +CType::TypesEqual(JSObject* t1, JSObject* t2)
  1.3411 +{
  1.3412 +  JS_ASSERT(IsCType(t1) && IsCType(t2));
  1.3413 +
  1.3414 +  // Fast path: check for object equality.
  1.3415 +  if (t1 == t2)
  1.3416 +    return true;
  1.3417 +
  1.3418 +  // First, perform shallow comparison.
  1.3419 +  TypeCode c1 = GetTypeCode(t1);
  1.3420 +  TypeCode c2 = GetTypeCode(t2);
  1.3421 +  if (c1 != c2)
  1.3422 +    return false;
  1.3423 +
  1.3424 +  // Determine whether the types require shallow or deep comparison.
  1.3425 +  switch (c1) {
  1.3426 +  case TYPE_pointer: {
  1.3427 +    // Compare base types.
  1.3428 +    JSObject* b1 = PointerType::GetBaseType(t1);
  1.3429 +    JSObject* b2 = PointerType::GetBaseType(t2);
  1.3430 +    return TypesEqual(b1, b2);
  1.3431 +  }
  1.3432 +  case TYPE_function: {
  1.3433 +    FunctionInfo* f1 = FunctionType::GetFunctionInfo(t1);
  1.3434 +    FunctionInfo* f2 = FunctionType::GetFunctionInfo(t2);
  1.3435 +
  1.3436 +    // Compare abi, return type, and argument types.
  1.3437 +    if (f1->mABI != f2->mABI)
  1.3438 +      return false;
  1.3439 +
  1.3440 +    if (!TypesEqual(f1->mReturnType, f2->mReturnType))
  1.3441 +      return false;
  1.3442 +
  1.3443 +    if (f1->mArgTypes.length() != f2->mArgTypes.length())
  1.3444 +      return false;
  1.3445 +
  1.3446 +    if (f1->mIsVariadic != f2->mIsVariadic)
  1.3447 +      return false;
  1.3448 +
  1.3449 +    for (size_t i = 0; i < f1->mArgTypes.length(); ++i) {
  1.3450 +      if (!TypesEqual(f1->mArgTypes[i], f2->mArgTypes[i]))
  1.3451 +        return false;
  1.3452 +    }
  1.3453 +
  1.3454 +    return true;
  1.3455 +  }
  1.3456 +  case TYPE_array: {
  1.3457 +    // Compare length, then base types.
  1.3458 +    // An undefined length array matches other undefined length arrays.
  1.3459 +    size_t s1 = 0, s2 = 0;
  1.3460 +    bool d1 = ArrayType::GetSafeLength(t1, &s1);
  1.3461 +    bool d2 = ArrayType::GetSafeLength(t2, &s2);
  1.3462 +    if (d1 != d2 || (d1 && s1 != s2))
  1.3463 +      return false;
  1.3464 +
  1.3465 +    JSObject* b1 = ArrayType::GetBaseType(t1);
  1.3466 +    JSObject* b2 = ArrayType::GetBaseType(t2);
  1.3467 +    return TypesEqual(b1, b2);
  1.3468 +  }
  1.3469 +  case TYPE_struct:
  1.3470 +    // Require exact type object equality.
  1.3471 +    return false;
  1.3472 +  default:
  1.3473 +    // Shallow comparison is sufficient.
  1.3474 +    return true;
  1.3475 +  }
  1.3476 +}
  1.3477 +
  1.3478 +bool
  1.3479 +CType::GetSafeSize(JSObject* obj, size_t* result)
  1.3480 +{
  1.3481 +  JS_ASSERT(CType::IsCType(obj));
  1.3482 +
  1.3483 +  jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  1.3484 +
  1.3485 +  // The "size" property can be an int, a double, or JSVAL_VOID
  1.3486 +  // (for arrays of undefined length), and must always fit in a size_t.
  1.3487 +  if (JSVAL_IS_INT(size)) {
  1.3488 +    *result = JSVAL_TO_INT(size);
  1.3489 +    return true;
  1.3490 +  }
  1.3491 +  if (JSVAL_IS_DOUBLE(size)) {
  1.3492 +    *result = Convert<size_t>(JSVAL_TO_DOUBLE(size));
  1.3493 +    return true;
  1.3494 +  }
  1.3495 +
  1.3496 +  JS_ASSERT(JSVAL_IS_VOID(size));
  1.3497 +  return false;
  1.3498 +}
  1.3499 +
  1.3500 +size_t
  1.3501 +CType::GetSize(JSObject* obj)
  1.3502 +{
  1.3503 +  JS_ASSERT(CType::IsCType(obj));
  1.3504 +
  1.3505 +  jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  1.3506 +
  1.3507 +  JS_ASSERT(!JSVAL_IS_VOID(size));
  1.3508 +
  1.3509 +  // The "size" property can be an int, a double, or JSVAL_VOID
  1.3510 +  // (for arrays of undefined length), and must always fit in a size_t.
  1.3511 +  // For callers who know it can never be JSVAL_VOID, return a size_t directly.
  1.3512 +  if (JSVAL_IS_INT(size))
  1.3513 +    return JSVAL_TO_INT(size);
  1.3514 +  return Convert<size_t>(JSVAL_TO_DOUBLE(size));
  1.3515 +}
  1.3516 +
  1.3517 +bool
  1.3518 +CType::IsSizeDefined(JSObject* obj)
  1.3519 +{
  1.3520 +  JS_ASSERT(CType::IsCType(obj));
  1.3521 +
  1.3522 +  jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  1.3523 +
  1.3524 +  // The "size" property can be an int, a double, or JSVAL_VOID
  1.3525 +  // (for arrays of undefined length), and must always fit in a size_t.
  1.3526 +  JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
  1.3527 +  return !JSVAL_IS_VOID(size);
  1.3528 +}
  1.3529 +
  1.3530 +size_t
  1.3531 +CType::GetAlignment(JSObject* obj)
  1.3532 +{
  1.3533 +  JS_ASSERT(CType::IsCType(obj));
  1.3534 +
  1.3535 +  jsval slot = JS_GetReservedSlot(obj, SLOT_ALIGN);
  1.3536 +  return static_cast<size_t>(JSVAL_TO_INT(slot));
  1.3537 +}
  1.3538 +
  1.3539 +ffi_type*
  1.3540 +CType::GetFFIType(JSContext* cx, JSObject* obj)
  1.3541 +{
  1.3542 +  JS_ASSERT(CType::IsCType(obj));
  1.3543 +
  1.3544 +  jsval slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
  1.3545 +
  1.3546 +  if (!JSVAL_IS_VOID(slot)) {
  1.3547 +    return static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
  1.3548 +  }
  1.3549 +
  1.3550 +  AutoPtr<ffi_type> result;
  1.3551 +  switch (CType::GetTypeCode(obj)) {
  1.3552 +  case TYPE_array:
  1.3553 +    result = ArrayType::BuildFFIType(cx, obj);
  1.3554 +    break;
  1.3555 +
  1.3556 +  case TYPE_struct:
  1.3557 +    result = StructType::BuildFFIType(cx, obj);
  1.3558 +    break;
  1.3559 +
  1.3560 +  default:
  1.3561 +    MOZ_ASSUME_UNREACHABLE("simple types must have an ffi_type");
  1.3562 +  }
  1.3563 +
  1.3564 +  if (!result)
  1.3565 +    return nullptr;
  1.3566 +  JS_SetReservedSlot(obj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(result.get()));
  1.3567 +  return result.forget();
  1.3568 +}
  1.3569 +
  1.3570 +JSString*
  1.3571 +CType::GetName(JSContext* cx, HandleObject obj)
  1.3572 +{
  1.3573 +  JS_ASSERT(CType::IsCType(obj));
  1.3574 +
  1.3575 +  jsval string = JS_GetReservedSlot(obj, SLOT_NAME);
  1.3576 +  if (!JSVAL_IS_VOID(string))
  1.3577 +    return JSVAL_TO_STRING(string);
  1.3578 +
  1.3579 +  // Build the type name lazily.
  1.3580 +  JSString* name = BuildTypeName(cx, obj);
  1.3581 +  if (!name)
  1.3582 +    return nullptr;
  1.3583 +  JS_SetReservedSlot(obj, SLOT_NAME, STRING_TO_JSVAL(name));
  1.3584 +  return name;
  1.3585 +}
  1.3586 +
  1.3587 +JSObject*
  1.3588 +CType::GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot)
  1.3589 +{
  1.3590 +  // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot
  1.3591 +  // on the type constructor.
  1.3592 +  jsval protoslot = js::GetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO);
  1.3593 +  JSObject* proto = &protoslot.toObject();
  1.3594 +  JS_ASSERT(proto);
  1.3595 +  JS_ASSERT(CType::IsCTypeProto(proto));
  1.3596 +
  1.3597 +  // Get the desired prototype.
  1.3598 +  jsval result = JS_GetReservedSlot(proto, slot);
  1.3599 +  return &result.toObject();
  1.3600 +}
  1.3601 +
  1.3602 +JSObject*
  1.3603 +CType::GetProtoFromType(JSContext* cx, JSObject* objArg, CTypeProtoSlot slot)
  1.3604 +{
  1.3605 +  JS_ASSERT(IsCType(objArg));
  1.3606 +  RootedObject obj(cx, objArg);
  1.3607 +
  1.3608 +  // Get the prototype of the type object.
  1.3609 +  RootedObject proto(cx);
  1.3610 +  if (!JS_GetPrototype(cx, obj, &proto))
  1.3611 +    return nullptr;
  1.3612 +  JS_ASSERT(proto);
  1.3613 +  JS_ASSERT(CType::IsCTypeProto(proto));
  1.3614 +
  1.3615 +  // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype.
  1.3616 +  jsval result = JS_GetReservedSlot(proto, slot);
  1.3617 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(result));
  1.3618 +  return JSVAL_TO_OBJECT(result);
  1.3619 +}
  1.3620 +
  1.3621 +bool
  1.3622 +CType::IsCTypeOrProto(HandleValue v)
  1.3623 +{
  1.3624 +  if (!v.isObject())
  1.3625 +    return false;
  1.3626 +  JSObject* obj = &v.toObject();
  1.3627 +  return CType::IsCType(obj) || CType::IsCTypeProto(obj);
  1.3628 +}
  1.3629 +
  1.3630 +bool
  1.3631 +CType::PrototypeGetter(JSContext* cx, JS::CallArgs args)
  1.3632 +{
  1.3633 +  RootedObject obj(cx, &args.thisv().toObject());
  1.3634 +  unsigned slot = CType::IsCTypeProto(obj) ? (unsigned) SLOT_OURDATAPROTO
  1.3635 +                                           : (unsigned) SLOT_PROTO;
  1.3636 +  args.rval().set(JS_GetReservedSlot(obj, slot));
  1.3637 +  MOZ_ASSERT(args.rval().isObject() || args.rval().isUndefined());
  1.3638 +  return true;
  1.3639 +}
  1.3640 +
  1.3641 +bool
  1.3642 +CType::IsCType(HandleValue v)
  1.3643 +{
  1.3644 +  return v.isObject() && CType::IsCType(&v.toObject());
  1.3645 +}
  1.3646 +
  1.3647 +bool
  1.3648 +CType::NameGetter(JSContext* cx, JS::CallArgs args)
  1.3649 +{
  1.3650 +  RootedObject obj(cx, &args.thisv().toObject());
  1.3651 +  JSString* name = CType::GetName(cx, obj);
  1.3652 +  if (!name)
  1.3653 +    return false;
  1.3654 +
  1.3655 +  args.rval().setString(name);
  1.3656 +  return true;
  1.3657 +}
  1.3658 +
  1.3659 +bool
  1.3660 +CType::SizeGetter(JSContext* cx, JS::CallArgs args)
  1.3661 +{
  1.3662 +  RootedObject obj(cx, &args.thisv().toObject());
  1.3663 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_SIZE));
  1.3664 +  MOZ_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
  1.3665 +  return true;
  1.3666 +}
  1.3667 +
  1.3668 +bool
  1.3669 +CType::PtrGetter(JSContext* cx, JS::CallArgs args)
  1.3670 +{
  1.3671 +  RootedObject obj(cx, &args.thisv().toObject());
  1.3672 +  JSObject* pointerType = PointerType::CreateInternal(cx, obj);
  1.3673 +  if (!pointerType)
  1.3674 +    return false;
  1.3675 +
  1.3676 +  args.rval().setObject(*pointerType);
  1.3677 +  return true;
  1.3678 +}
  1.3679 +
  1.3680 +bool
  1.3681 +CType::CreateArray(JSContext* cx, unsigned argc, jsval* vp)
  1.3682 +{
  1.3683 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3684 +  RootedObject baseType(cx, JS_THIS_OBJECT(cx, vp));
  1.3685 +  if (!baseType)
  1.3686 +    return false;
  1.3687 +  if (!CType::IsCType(baseType)) {
  1.3688 +    JS_ReportError(cx, "not a CType");
  1.3689 +    return false;
  1.3690 +  }
  1.3691 +
  1.3692 +  // Construct and return a new ArrayType object.
  1.3693 +  if (args.length() > 1) {
  1.3694 +    JS_ReportError(cx, "array takes zero or one argument");
  1.3695 +    return false;
  1.3696 +  }
  1.3697 +
  1.3698 +  // Convert the length argument to a size_t.
  1.3699 +  size_t length = 0;
  1.3700 +  if (args.length() == 1 && !jsvalToSize(cx, args[0], false, &length)) {
  1.3701 +    JS_ReportError(cx, "argument must be a nonnegative integer");
  1.3702 +    return false;
  1.3703 +  }
  1.3704 +
  1.3705 +  JSObject* result = ArrayType::CreateInternal(cx, baseType, length, args.length() == 1);
  1.3706 +  if (!result)
  1.3707 +    return false;
  1.3708 +
  1.3709 +  args.rval().setObject(*result);
  1.3710 +  return true;
  1.3711 +}
  1.3712 +
  1.3713 +bool
  1.3714 +CType::ToString(JSContext* cx, unsigned argc, jsval* vp)
  1.3715 +{
  1.3716 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3717 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.3718 +  if (!obj)
  1.3719 +    return false;
  1.3720 +  if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
  1.3721 +    JS_ReportError(cx, "not a CType");
  1.3722 +    return false;
  1.3723 +  }
  1.3724 +
  1.3725 +  // Create the appropriate string depending on whether we're sCTypeClass or
  1.3726 +  // sCTypeProtoClass.
  1.3727 +  JSString* result;
  1.3728 +  if (CType::IsCType(obj)) {
  1.3729 +    AutoString type;
  1.3730 +    AppendString(type, "type ");
  1.3731 +    AppendString(type, GetName(cx, obj));
  1.3732 +    result = NewUCString(cx, type);
  1.3733 +  }
  1.3734 +  else {
  1.3735 +    result = JS_NewStringCopyZ(cx, "[CType proto object]");
  1.3736 +  }
  1.3737 +  if (!result)
  1.3738 +    return false;
  1.3739 +
  1.3740 +  args.rval().setString(result);
  1.3741 +  return true;
  1.3742 +}
  1.3743 +
  1.3744 +bool
  1.3745 +CType::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  1.3746 +{
  1.3747 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3748 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.3749 +  if (!obj)
  1.3750 +    return false;
  1.3751 +  if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj))
  1.3752 +  {
  1.3753 +    JS_ReportError(cx, "not a CType");
  1.3754 +    return false;
  1.3755 +  }
  1.3756 +
  1.3757 +  // Create the appropriate string depending on whether we're sCTypeClass or
  1.3758 +  // sCTypeProtoClass.
  1.3759 +  JSString* result;
  1.3760 +  if (CType::IsCType(obj)) {
  1.3761 +    AutoString source;
  1.3762 +    BuildTypeSource(cx, obj, false, source);
  1.3763 +    result = NewUCString(cx, source);
  1.3764 +  } else {
  1.3765 +    result = JS_NewStringCopyZ(cx, "[CType proto object]");
  1.3766 +  }
  1.3767 +  if (!result)
  1.3768 +    return false;
  1.3769 +
  1.3770 +  args.rval().setString(result);
  1.3771 +  return true;
  1.3772 +}
  1.3773 +
  1.3774 +bool
  1.3775 +CType::HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
  1.3776 +{
  1.3777 +  JS_ASSERT(CType::IsCType(obj));
  1.3778 +
  1.3779 +  jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO);
  1.3780 +  JS::Rooted<JSObject*> prototype(cx, &slot.toObject());
  1.3781 +  JS_ASSERT(prototype);
  1.3782 +  JS_ASSERT(CData::IsCDataProto(prototype));
  1.3783 +
  1.3784 +  *bp = false;
  1.3785 +  if (JSVAL_IS_PRIMITIVE(v))
  1.3786 +    return true;
  1.3787 +
  1.3788 +  RootedObject proto(cx, &v.toObject());
  1.3789 +  for (;;) {
  1.3790 +    if (!JS_GetPrototype(cx, proto, &proto))
  1.3791 +      return false;
  1.3792 +    if (!proto)
  1.3793 +      break;
  1.3794 +    if (proto == prototype) {
  1.3795 +      *bp = true;
  1.3796 +      break;
  1.3797 +    }
  1.3798 +  }
  1.3799 +  return true;
  1.3800 +}
  1.3801 +
  1.3802 +static JSObject*
  1.3803 +CType::GetGlobalCTypes(JSContext* cx, JSObject* objArg)
  1.3804 +{
  1.3805 +  JS_ASSERT(CType::IsCType(objArg));
  1.3806 +
  1.3807 +  RootedObject obj(cx, objArg);
  1.3808 +  RootedObject objTypeProto(cx);
  1.3809 +  if (!JS_GetPrototype(cx, obj, &objTypeProto))
  1.3810 +    return nullptr;
  1.3811 +  JS_ASSERT(objTypeProto);
  1.3812 +  JS_ASSERT(CType::IsCTypeProto(objTypeProto));
  1.3813 +
  1.3814 +  jsval valCTypes = JS_GetReservedSlot(objTypeProto, SLOT_CTYPES);
  1.3815 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
  1.3816 +
  1.3817 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
  1.3818 +  return &valCTypes.toObject();
  1.3819 +}
  1.3820 +
  1.3821 +/*******************************************************************************
  1.3822 +** ABI implementation
  1.3823 +*******************************************************************************/
  1.3824 +
  1.3825 +bool
  1.3826 +ABI::IsABI(JSObject* obj)
  1.3827 +{
  1.3828 +  return JS_GetClass(obj) == &sCABIClass;
  1.3829 +}
  1.3830 +
  1.3831 +bool
  1.3832 +ABI::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  1.3833 +{
  1.3834 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3835 +  if (args.length() != 0) {
  1.3836 +    JS_ReportError(cx, "toSource takes zero arguments");
  1.3837 +    return false;
  1.3838 +  }
  1.3839 +
  1.3840 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.3841 +  if (!obj)
  1.3842 +    return false;
  1.3843 +  if (!ABI::IsABI(obj)) {
  1.3844 +    JS_ReportError(cx, "not an ABI");
  1.3845 +    return false;
  1.3846 +  }
  1.3847 +
  1.3848 +  JSString* result;
  1.3849 +  switch (GetABICode(obj)) {
  1.3850 +    case ABI_DEFAULT:
  1.3851 +      result = JS_NewStringCopyZ(cx, "ctypes.default_abi");
  1.3852 +      break;
  1.3853 +    case ABI_STDCALL:
  1.3854 +      result = JS_NewStringCopyZ(cx, "ctypes.stdcall_abi");
  1.3855 +      break;
  1.3856 +    case ABI_WINAPI:
  1.3857 +      result = JS_NewStringCopyZ(cx, "ctypes.winapi_abi");
  1.3858 +      break;
  1.3859 +    default:
  1.3860 +      JS_ReportError(cx, "not a valid ABICode");
  1.3861 +      return false;
  1.3862 +  }
  1.3863 +  if (!result)
  1.3864 +    return false;
  1.3865 +
  1.3866 +  args.rval().setString(result);
  1.3867 +  return true;
  1.3868 +}
  1.3869 +
  1.3870 +
  1.3871 +/*******************************************************************************
  1.3872 +** PointerType implementation
  1.3873 +*******************************************************************************/
  1.3874 +
  1.3875 +bool
  1.3876 +PointerType::Create(JSContext* cx, unsigned argc, jsval* vp)
  1.3877 +{
  1.3878 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.3879 +  // Construct and return a new PointerType object.
  1.3880 +  if (args.length() != 1) {
  1.3881 +    JS_ReportError(cx, "PointerType takes one argument");
  1.3882 +    return false;
  1.3883 +  }
  1.3884 +
  1.3885 +  jsval arg = args[0];
  1.3886 +  RootedObject obj(cx);
  1.3887 +  if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(obj = &arg.toObject())) {
  1.3888 +    JS_ReportError(cx, "first argument must be a CType");
  1.3889 +    return false;
  1.3890 +  }
  1.3891 +
  1.3892 +  JSObject* result = CreateInternal(cx, obj);
  1.3893 +  if (!result)
  1.3894 +    return false;
  1.3895 +
  1.3896 +  args.rval().setObject(*result);
  1.3897 +  return true;
  1.3898 +}
  1.3899 +
  1.3900 +JSObject*
  1.3901 +PointerType::CreateInternal(JSContext* cx, HandleObject baseType)
  1.3902 +{
  1.3903 +  // check if we have a cached PointerType on our base CType.
  1.3904 +  jsval slot = JS_GetReservedSlot(baseType, SLOT_PTR);
  1.3905 +  if (!slot.isUndefined())
  1.3906 +    return &slot.toObject();
  1.3907 +
  1.3908 +  // Get ctypes.PointerType.prototype and the common prototype for CData objects
  1.3909 +  // of this type, or ctypes.FunctionType.prototype for function pointers.
  1.3910 +  CTypeProtoSlot slotId = CType::GetTypeCode(baseType) == TYPE_function ?
  1.3911 +    SLOT_FUNCTIONDATAPROTO : SLOT_POINTERDATAPROTO;
  1.3912 +  RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, slotId));
  1.3913 +  if (!dataProto)
  1.3914 +    return nullptr;
  1.3915 +  RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO));
  1.3916 +  if (!typeProto)
  1.3917 +    return nullptr;
  1.3918 +
  1.3919 +  // Create a new CType object with the common properties and slots.
  1.3920 +  JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer,
  1.3921 +                        nullptr, INT_TO_JSVAL(sizeof(void*)),
  1.3922 +                        INT_TO_JSVAL(ffi_type_pointer.alignment),
  1.3923 +                        &ffi_type_pointer);
  1.3924 +  if (!typeObj)
  1.3925 +    return nullptr;
  1.3926 +
  1.3927 +  // Set the target type. (This will be 'null' for an opaque pointer type.)
  1.3928 +  JS_SetReservedSlot(typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType));
  1.3929 +
  1.3930 +  // Finally, cache our newly-created PointerType on our pointed-to CType.
  1.3931 +  JS_SetReservedSlot(baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj));
  1.3932 +
  1.3933 +  return typeObj;
  1.3934 +}
  1.3935 +
  1.3936 +bool
  1.3937 +PointerType::ConstructData(JSContext* cx,
  1.3938 +                           HandleObject obj,
  1.3939 +                           const CallArgs& args)
  1.3940 +{
  1.3941 +  if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_pointer) {
  1.3942 +    JS_ReportError(cx, "not a PointerType");
  1.3943 +    return false;
  1.3944 +  }
  1.3945 +
  1.3946 +  if (args.length() > 3) {
  1.3947 +    JS_ReportError(cx, "constructor takes 0, 1, 2, or 3 arguments");
  1.3948 +    return false;
  1.3949 +  }
  1.3950 +
  1.3951 +  RootedObject result(cx, CData::Create(cx, obj, NullPtr(), nullptr, true));
  1.3952 +  if (!result)
  1.3953 +    return false;
  1.3954 +
  1.3955 +  // Set return value early, must not observe *vp after
  1.3956 +  args.rval().setObject(*result);
  1.3957 +
  1.3958 +  // There are 3 things that we might be creating here:
  1.3959 +  // 1 - A null pointer (no arguments)
  1.3960 +  // 2 - An initialized pointer (1 argument)
  1.3961 +  // 3 - A closure (1-3 arguments)
  1.3962 +  //
  1.3963 +  // The API doesn't give us a perfect way to distinguish 2 and 3, but the
  1.3964 +  // heuristics we use should be fine.
  1.3965 +
  1.3966 +  //
  1.3967 +  // Case 1 - Null pointer
  1.3968 +  //
  1.3969 +  if (args.length() == 0)
  1.3970 +    return true;
  1.3971 +
  1.3972 +  // Analyze the arguments a bit to decide what to do next.
  1.3973 +  RootedObject baseObj(cx, PointerType::GetBaseType(obj));
  1.3974 +  bool looksLikeClosure = CType::GetTypeCode(baseObj) == TYPE_function &&
  1.3975 +                          args[0].isObject() &&
  1.3976 +                          JS_ObjectIsCallable(cx, &args[0].toObject());
  1.3977 +
  1.3978 +  //
  1.3979 +  // Case 2 - Initialized pointer
  1.3980 +  //
  1.3981 +  if (!looksLikeClosure) {
  1.3982 +    if (args.length() != 1) {
  1.3983 +      JS_ReportError(cx, "first argument must be a function");
  1.3984 +      return false;
  1.3985 +    }
  1.3986 +    return ExplicitConvert(cx, args[0], obj, CData::GetData(result));
  1.3987 +  }
  1.3988 +
  1.3989 +  //
  1.3990 +  // Case 3 - Closure
  1.3991 +  //
  1.3992 +
  1.3993 +  // The second argument is an optional 'this' parameter with which to invoke
  1.3994 +  // the given js function. Callers may leave this blank, or pass null if they
  1.3995 +  // wish to pass the third argument.
  1.3996 +  RootedObject thisObj(cx, nullptr);
  1.3997 +  if (args.length() >= 2) {
  1.3998 +    if (args[1].isNull()) {
  1.3999 +      thisObj = nullptr;
  1.4000 +    } else if (!JSVAL_IS_PRIMITIVE(args[1])) {
  1.4001 +      thisObj = &args[1].toObject();
  1.4002 +    } else if (!JS_ValueToObject(cx, args[1], &thisObj)) {
  1.4003 +      return false;
  1.4004 +    }
  1.4005 +  }
  1.4006 +
  1.4007 +  // The third argument is an optional error sentinel that js-ctypes will return
  1.4008 +  // if an exception is raised while executing the closure. The type must match
  1.4009 +  // the return type of the callback.
  1.4010 +  jsval errVal = JSVAL_VOID;
  1.4011 +  if (args.length() == 3)
  1.4012 +    errVal = args[2];
  1.4013 +
  1.4014 +  RootedObject fnObj(cx, &args[0].toObject());
  1.4015 +  return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj, errVal);
  1.4016 +}
  1.4017 +
  1.4018 +JSObject*
  1.4019 +PointerType::GetBaseType(JSObject* obj)
  1.4020 +{
  1.4021 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_pointer);
  1.4022 +
  1.4023 +  jsval type = JS_GetReservedSlot(obj, SLOT_TARGET_T);
  1.4024 +  JS_ASSERT(!type.isNull());
  1.4025 +  return &type.toObject();
  1.4026 +}
  1.4027 +
  1.4028 +bool
  1.4029 +PointerType::IsPointerType(HandleValue v)
  1.4030 +{
  1.4031 +  if (!v.isObject())
  1.4032 +    return false;
  1.4033 +  JSObject* obj = &v.toObject();
  1.4034 +  return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_pointer;
  1.4035 +}
  1.4036 +
  1.4037 +bool
  1.4038 +PointerType::IsPointer(HandleValue v)
  1.4039 +{
  1.4040 +  if (!v.isObject())
  1.4041 +    return false;
  1.4042 +  JSObject* obj = &v.toObject();
  1.4043 +  return CData::IsCData(obj) && CType::GetTypeCode(CData::GetCType(obj)) == TYPE_pointer;
  1.4044 +}
  1.4045 +
  1.4046 +bool
  1.4047 +PointerType::TargetTypeGetter(JSContext* cx, JS::CallArgs args)
  1.4048 +{
  1.4049 +  RootedObject obj(cx, &args.thisv().toObject());
  1.4050 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_TARGET_T));
  1.4051 +  MOZ_ASSERT(args.rval().isObject());
  1.4052 +  return true;
  1.4053 +}
  1.4054 +
  1.4055 +bool
  1.4056 +PointerType::IsNull(JSContext* cx, unsigned argc, jsval* vp)
  1.4057 +{
  1.4058 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4059 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.4060 +  if (!obj)
  1.4061 +    return false;
  1.4062 +  if (!CData::IsCData(obj)) {
  1.4063 +    JS_ReportError(cx, "not a CData");
  1.4064 +    return false;
  1.4065 +  }
  1.4066 +
  1.4067 +  // Get pointer type and base type.
  1.4068 +  JSObject* typeObj = CData::GetCType(obj);
  1.4069 +  if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  1.4070 +    JS_ReportError(cx, "not a PointerType");
  1.4071 +    return false;
  1.4072 +  }
  1.4073 +
  1.4074 +  void* data = *static_cast<void**>(CData::GetData(obj));
  1.4075 +  args.rval().setBoolean(data == nullptr);
  1.4076 +  return true;
  1.4077 +}
  1.4078 +
  1.4079 +bool
  1.4080 +PointerType::OffsetBy(JSContext* cx, const CallArgs& args, int offset)
  1.4081 +{
  1.4082 +  JSObject* obj = JS_THIS_OBJECT(cx, args.base());
  1.4083 +  if (!obj)
  1.4084 +    return false;
  1.4085 +  if (!CData::IsCData(obj)) {
  1.4086 +    JS_ReportError(cx, "not a CData");
  1.4087 +    return false;
  1.4088 +  }
  1.4089 +
  1.4090 +  RootedObject typeObj(cx, CData::GetCType(obj));
  1.4091 +  if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  1.4092 +    JS_ReportError(cx, "not a PointerType");
  1.4093 +    return false;
  1.4094 +  }
  1.4095 +
  1.4096 +  RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
  1.4097 +  if (!CType::IsSizeDefined(baseType)) {
  1.4098 +    JS_ReportError(cx, "cannot modify pointer of undefined size");
  1.4099 +    return false;
  1.4100 +  }
  1.4101 +
  1.4102 +  size_t elementSize = CType::GetSize(baseType);
  1.4103 +  char* data = static_cast<char*>(*static_cast<void**>(CData::GetData(obj)));
  1.4104 +  void* address = data + offset * elementSize;
  1.4105 +
  1.4106 +  // Create a PointerType CData object containing the new address.
  1.4107 +  JSObject* result = CData::Create(cx, typeObj, NullPtr(), &address, true);
  1.4108 +  if (!result)
  1.4109 +    return false;
  1.4110 +
  1.4111 +  args.rval().setObject(*result);
  1.4112 +  return true;
  1.4113 +}
  1.4114 +
  1.4115 +bool
  1.4116 +PointerType::Increment(JSContext* cx, unsigned argc, jsval* vp)
  1.4117 +{
  1.4118 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4119 +  return OffsetBy(cx, args, 1);
  1.4120 +}
  1.4121 +
  1.4122 +bool
  1.4123 +PointerType::Decrement(JSContext* cx, unsigned argc, jsval* vp)
  1.4124 +{
  1.4125 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4126 +  return OffsetBy(cx, args, -1);
  1.4127 +}
  1.4128 +
  1.4129 +bool
  1.4130 +PointerType::ContentsGetter(JSContext* cx, JS::CallArgs args)
  1.4131 +{
  1.4132 +  RootedObject obj(cx, &args.thisv().toObject());
  1.4133 +  RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
  1.4134 +  if (!CType::IsSizeDefined(baseType)) {
  1.4135 +    JS_ReportError(cx, "cannot get contents of undefined size");
  1.4136 +    return false;
  1.4137 +  }
  1.4138 +
  1.4139 +  void* data = *static_cast<void**>(CData::GetData(obj));
  1.4140 +  if (data == nullptr) {
  1.4141 +    JS_ReportError(cx, "cannot read contents of null pointer");
  1.4142 +    return false;
  1.4143 +  }
  1.4144 +
  1.4145 +  RootedValue result(cx);
  1.4146 +  if (!ConvertToJS(cx, baseType, NullPtr(), data, false, false, result.address()))
  1.4147 +    return false;
  1.4148 +
  1.4149 +  args.rval().set(result);
  1.4150 +  return true;
  1.4151 +}
  1.4152 +
  1.4153 +bool
  1.4154 +PointerType::ContentsSetter(JSContext* cx, JS::CallArgs args)
  1.4155 +{
  1.4156 +  RootedObject obj(cx, &args.thisv().toObject());
  1.4157 +  RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
  1.4158 +  if (!CType::IsSizeDefined(baseType)) {
  1.4159 +    JS_ReportError(cx, "cannot set contents of undefined size");
  1.4160 +    return false;
  1.4161 +  }
  1.4162 +
  1.4163 +  void* data = *static_cast<void**>(CData::GetData(obj));
  1.4164 +  if (data == nullptr) {
  1.4165 +    JS_ReportError(cx, "cannot write contents to null pointer");
  1.4166 +    return false;
  1.4167 +  }
  1.4168 +
  1.4169 +  args.rval().setUndefined();
  1.4170 +  return ImplicitConvert(cx, args.get(0), baseType, data, false, nullptr);
  1.4171 +}
  1.4172 +
  1.4173 +/*******************************************************************************
  1.4174 +** ArrayType implementation
  1.4175 +*******************************************************************************/
  1.4176 +
  1.4177 +bool
  1.4178 +ArrayType::Create(JSContext* cx, unsigned argc, jsval* vp)
  1.4179 +{
  1.4180 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4181 +  // Construct and return a new ArrayType object.
  1.4182 +  if (args.length() < 1 || args.length() > 2) {
  1.4183 +    JS_ReportError(cx, "ArrayType takes one or two arguments");
  1.4184 +    return false;
  1.4185 +  }
  1.4186 +
  1.4187 +  if (JSVAL_IS_PRIMITIVE(args[0]) ||
  1.4188 +      !CType::IsCType(&args[0].toObject())) {
  1.4189 +    JS_ReportError(cx, "first argument must be a CType");
  1.4190 +    return false;
  1.4191 +  }
  1.4192 +
  1.4193 +  // Convert the length argument to a size_t.
  1.4194 +  size_t length = 0;
  1.4195 +  if (args.length() == 2 && !jsvalToSize(cx, args[1], false, &length)) {
  1.4196 +    JS_ReportError(cx, "second argument must be a nonnegative integer");
  1.4197 +    return false;
  1.4198 +  }
  1.4199 +
  1.4200 +  RootedObject baseType(cx, &args[0].toObject());
  1.4201 +  JSObject* result = CreateInternal(cx, baseType, length, args.length() == 2);
  1.4202 +  if (!result)
  1.4203 +    return false;
  1.4204 +
  1.4205 +  args.rval().setObject(*result);
  1.4206 +  return true;
  1.4207 +}
  1.4208 +
  1.4209 +JSObject*
  1.4210 +ArrayType::CreateInternal(JSContext* cx,
  1.4211 +                          HandleObject baseType,
  1.4212 +                          size_t length,
  1.4213 +                          bool lengthDefined)
  1.4214 +{
  1.4215 +  // Get ctypes.ArrayType.prototype and the common prototype for CData objects
  1.4216 +  // of this type, from ctypes.CType.prototype.
  1.4217 +  RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYPROTO));
  1.4218 +  if (!typeProto)
  1.4219 +    return nullptr;
  1.4220 +  RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYDATAPROTO));
  1.4221 +  if (!dataProto)
  1.4222 +    return nullptr;
  1.4223 +
  1.4224 +  // Determine the size of the array from the base type, if possible.
  1.4225 +  // The size of the base type must be defined.
  1.4226 +  // If our length is undefined, both our size and length will be undefined.
  1.4227 +  size_t baseSize;
  1.4228 +  if (!CType::GetSafeSize(baseType, &baseSize)) {
  1.4229 +    JS_ReportError(cx, "base size must be defined");
  1.4230 +    return nullptr;
  1.4231 +  }
  1.4232 +
  1.4233 +  RootedValue sizeVal(cx, JSVAL_VOID);
  1.4234 +  RootedValue lengthVal(cx, JSVAL_VOID);
  1.4235 +  if (lengthDefined) {
  1.4236 +    // Check for overflow, and convert to an int or double as required.
  1.4237 +    size_t size = length * baseSize;
  1.4238 +    if (length > 0 && size / length != baseSize) {
  1.4239 +      JS_ReportError(cx, "size overflow");
  1.4240 +      return nullptr;
  1.4241 +    }
  1.4242 +    if (!SizeTojsval(cx, size, sizeVal.address()) ||
  1.4243 +        !SizeTojsval(cx, length, lengthVal.address()))
  1.4244 +      return nullptr;
  1.4245 +  }
  1.4246 +
  1.4247 +  size_t align = CType::GetAlignment(baseType);
  1.4248 +
  1.4249 +  // Create a new CType object with the common properties and slots.
  1.4250 +  JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_array, nullptr,
  1.4251 +                        sizeVal, INT_TO_JSVAL(align), nullptr);
  1.4252 +  if (!typeObj)
  1.4253 +    return nullptr;
  1.4254 +
  1.4255 +  // Set the element type.
  1.4256 +  JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType));
  1.4257 +
  1.4258 +  // Set the length.
  1.4259 +  JS_SetReservedSlot(typeObj, SLOT_LENGTH, lengthVal);
  1.4260 +
  1.4261 +  return typeObj;
  1.4262 +}
  1.4263 +
  1.4264 +bool
  1.4265 +ArrayType::ConstructData(JSContext* cx,
  1.4266 +                         HandleObject obj_,
  1.4267 +                         const CallArgs& args)
  1.4268 +{
  1.4269 +  RootedObject obj(cx, obj_); // Make a mutable version
  1.4270 +
  1.4271 +  if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
  1.4272 +    JS_ReportError(cx, "not an ArrayType");
  1.4273 +    return false;
  1.4274 +  }
  1.4275 +
  1.4276 +  // Decide whether we have an object to initialize from. We'll override this
  1.4277 +  // if we get a length argument instead.
  1.4278 +  bool convertObject = args.length() == 1;
  1.4279 +
  1.4280 +  // Check if we're an array of undefined length. If we are, allow construction
  1.4281 +  // with a length argument, or with an actual JS array.
  1.4282 +  if (CType::IsSizeDefined(obj)) {
  1.4283 +    if (args.length() > 1) {
  1.4284 +      JS_ReportError(cx, "constructor takes zero or one argument");
  1.4285 +      return false;
  1.4286 +    }
  1.4287 +
  1.4288 +  } else {
  1.4289 +    if (args.length() != 1) {
  1.4290 +      JS_ReportError(cx, "constructor takes one argument");
  1.4291 +      return false;
  1.4292 +    }
  1.4293 +
  1.4294 +    RootedObject baseType(cx, GetBaseType(obj));
  1.4295 +
  1.4296 +    size_t length;
  1.4297 +    if (jsvalToSize(cx, args[0], false, &length)) {
  1.4298 +      // Have a length, rather than an object to initialize from.
  1.4299 +      convertObject = false;
  1.4300 +
  1.4301 +    } else if (!JSVAL_IS_PRIMITIVE(args[0])) {
  1.4302 +      // We were given an object with a .length property.
  1.4303 +      // This could be a JS array, or a CData array.
  1.4304 +      RootedObject arg(cx, &args[0].toObject());
  1.4305 +      RootedValue lengthVal(cx);
  1.4306 +      if (!JS_GetProperty(cx, arg, "length", &lengthVal) ||
  1.4307 +          !jsvalToSize(cx, lengthVal, false, &length)) {
  1.4308 +        JS_ReportError(cx, "argument must be an array object or length");
  1.4309 +        return false;
  1.4310 +      }
  1.4311 +
  1.4312 +    } else if (args[0].isString()) {
  1.4313 +      // We were given a string. Size the array to the appropriate length,
  1.4314 +      // including space for the terminator.
  1.4315 +      JSString* sourceString = args[0].toString();
  1.4316 +      size_t sourceLength = sourceString->length();
  1.4317 +      const jschar* sourceChars = sourceString->getChars(cx);
  1.4318 +      if (!sourceChars)
  1.4319 +        return false;
  1.4320 +
  1.4321 +      switch (CType::GetTypeCode(baseType)) {
  1.4322 +      case TYPE_char:
  1.4323 +      case TYPE_signed_char:
  1.4324 +      case TYPE_unsigned_char: {
  1.4325 +        // Determine the UTF-8 length.
  1.4326 +        length = GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  1.4327 +        if (length == (size_t) -1)
  1.4328 +          return false;
  1.4329 +
  1.4330 +        ++length;
  1.4331 +        break;
  1.4332 +      }
  1.4333 +      case TYPE_jschar:
  1.4334 +        length = sourceLength + 1;
  1.4335 +        break;
  1.4336 +      default:
  1.4337 +        return TypeError(cx, "array", args[0]);
  1.4338 +      }
  1.4339 +
  1.4340 +    } else {
  1.4341 +      JS_ReportError(cx, "argument must be an array object or length");
  1.4342 +      return false;
  1.4343 +    }
  1.4344 +
  1.4345 +    // Construct a new ArrayType of defined length, for the new CData object.
  1.4346 +    obj = CreateInternal(cx, baseType, length, true);
  1.4347 +    if (!obj)
  1.4348 +      return false;
  1.4349 +  }
  1.4350 +
  1.4351 +  JSObject* result = CData::Create(cx, obj, NullPtr(), nullptr, true);
  1.4352 +  if (!result)
  1.4353 +    return false;
  1.4354 +
  1.4355 +  args.rval().setObject(*result);
  1.4356 +
  1.4357 +  if (convertObject) {
  1.4358 +    if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result)))
  1.4359 +      return false;
  1.4360 +  }
  1.4361 +
  1.4362 +  return true;
  1.4363 +}
  1.4364 +
  1.4365 +JSObject*
  1.4366 +ArrayType::GetBaseType(JSObject* obj)
  1.4367 +{
  1.4368 +  JS_ASSERT(CType::IsCType(obj));
  1.4369 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  1.4370 +
  1.4371 +  jsval type = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
  1.4372 +  JS_ASSERT(!JSVAL_IS_NULL(type));
  1.4373 +  return &type.toObject();
  1.4374 +}
  1.4375 +
  1.4376 +bool
  1.4377 +ArrayType::GetSafeLength(JSObject* obj, size_t* result)
  1.4378 +{
  1.4379 +  JS_ASSERT(CType::IsCType(obj));
  1.4380 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  1.4381 +
  1.4382 +  jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
  1.4383 +
  1.4384 +  // The "length" property can be an int, a double, or JSVAL_VOID
  1.4385 +  // (for arrays of undefined length), and must always fit in a size_t.
  1.4386 +  if (length.isInt32()) {
  1.4387 +    *result = length.toInt32();;
  1.4388 +    return true;
  1.4389 +  }
  1.4390 +  if (length.isDouble()) {
  1.4391 +    *result = Convert<size_t>(length.toDouble());
  1.4392 +    return true;
  1.4393 +  }
  1.4394 +
  1.4395 +  JS_ASSERT(length.isUndefined());
  1.4396 +  return false;
  1.4397 +}
  1.4398 +
  1.4399 +size_t
  1.4400 +ArrayType::GetLength(JSObject* obj)
  1.4401 +{
  1.4402 +  JS_ASSERT(CType::IsCType(obj));
  1.4403 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  1.4404 +
  1.4405 +  jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
  1.4406 +
  1.4407 +  JS_ASSERT(!length.isUndefined());
  1.4408 +
  1.4409 +  // The "length" property can be an int, a double, or JSVAL_VOID
  1.4410 +  // (for arrays of undefined length), and must always fit in a size_t.
  1.4411 +  // For callers who know it can never be JSVAL_VOID, return a size_t directly.
  1.4412 +  if (length.isInt32())
  1.4413 +    return length.toInt32();;
  1.4414 +  return Convert<size_t>(length.toDouble());
  1.4415 +}
  1.4416 +
  1.4417 +ffi_type*
  1.4418 +ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
  1.4419 +{
  1.4420 +  JS_ASSERT(CType::IsCType(obj));
  1.4421 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  1.4422 +  JS_ASSERT(CType::IsSizeDefined(obj));
  1.4423 +
  1.4424 +  JSObject* baseType = ArrayType::GetBaseType(obj);
  1.4425 +  ffi_type* ffiBaseType = CType::GetFFIType(cx, baseType);
  1.4426 +  if (!ffiBaseType)
  1.4427 +    return nullptr;
  1.4428 +
  1.4429 +  size_t length = ArrayType::GetLength(obj);
  1.4430 +
  1.4431 +  // Create an ffi_type to represent the array. This is necessary for the case
  1.4432 +  // where the array is part of a struct. Since libffi has no intrinsic
  1.4433 +  // support for array types, we approximate it by creating a struct type
  1.4434 +  // with elements of type 'baseType' and with appropriate size and alignment
  1.4435 +  // values. It would be nice to not do all the work of setting up 'elements',
  1.4436 +  // but some libffi platforms currently require that it be meaningful. I'm
  1.4437 +  // looking at you, x86_64.
  1.4438 +  AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
  1.4439 +  if (!ffiType) {
  1.4440 +    JS_ReportOutOfMemory(cx);
  1.4441 +    return nullptr;
  1.4442 +  }
  1.4443 +
  1.4444 +  ffiType->type = FFI_TYPE_STRUCT;
  1.4445 +  ffiType->size = CType::GetSize(obj);
  1.4446 +  ffiType->alignment = CType::GetAlignment(obj);
  1.4447 +  ffiType->elements = cx->pod_malloc<ffi_type*>(length + 1);
  1.4448 +  if (!ffiType->elements) {
  1.4449 +    JS_ReportAllocationOverflow(cx);
  1.4450 +    return nullptr;
  1.4451 +  }
  1.4452 +
  1.4453 +  for (size_t i = 0; i < length; ++i)
  1.4454 +    ffiType->elements[i] = ffiBaseType;
  1.4455 +  ffiType->elements[length] = nullptr;
  1.4456 +
  1.4457 +  return ffiType.forget();
  1.4458 +}
  1.4459 +
  1.4460 +bool
  1.4461 +ArrayType::IsArrayType(HandleValue v)
  1.4462 +{
  1.4463 +  if (!v.isObject())
  1.4464 +    return false;
  1.4465 +  JSObject* obj = &v.toObject();
  1.4466 +  return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
  1.4467 +}
  1.4468 +
  1.4469 +bool
  1.4470 +ArrayType::IsArrayOrArrayType(HandleValue v)
  1.4471 +{
  1.4472 +  if (!v.isObject())
  1.4473 +    return false;
  1.4474 +  JSObject* obj = &v.toObject();
  1.4475 +
  1.4476 +   // Allow both CTypes and CDatas of the ArrayType persuasion by extracting the
  1.4477 +   // CType if we're dealing with a CData.
  1.4478 +  if (CData::IsCData(obj)) {
  1.4479 +    obj = CData::GetCType(obj);
  1.4480 +  }
  1.4481 +  return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
  1.4482 +}
  1.4483 +
  1.4484 +bool
  1.4485 +ArrayType::ElementTypeGetter(JSContext* cx, JS::CallArgs args)
  1.4486 +{
  1.4487 +  RootedObject obj(cx, &args.thisv().toObject());
  1.4488 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_ELEMENT_T));
  1.4489 +  MOZ_ASSERT(args.rval().isObject());
  1.4490 +  return true;
  1.4491 +}
  1.4492 +
  1.4493 +bool
  1.4494 +ArrayType::LengthGetter(JSContext* cx, JS::CallArgs args)
  1.4495 +{
  1.4496 +  JSObject *obj = &args.thisv().toObject();
  1.4497 +
  1.4498 +  // This getter exists for both CTypes and CDatas of the ArrayType persuasion.
  1.4499 +  // If we're dealing with a CData, get the CType from it.
  1.4500 +  if (CData::IsCData(obj))
  1.4501 +    obj = CData::GetCType(obj);
  1.4502 +
  1.4503 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_LENGTH));
  1.4504 +  JS_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
  1.4505 +  return true;
  1.4506 +}
  1.4507 +
  1.4508 +bool
  1.4509 +ArrayType::Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp)
  1.4510 +{
  1.4511 +  // This should never happen, but we'll check to be safe.
  1.4512 +  if (!CData::IsCData(obj)) {
  1.4513 +    JS_ReportError(cx, "not a CData");
  1.4514 +    return false;
  1.4515 +  }
  1.4516 +
  1.4517 +  // Bail early if we're not an ArrayType. (This setter is present for all
  1.4518 +  // CData, regardless of CType.)
  1.4519 +  JSObject* typeObj = CData::GetCType(obj);
  1.4520 +  if (CType::GetTypeCode(typeObj) != TYPE_array)
  1.4521 +    return true;
  1.4522 +
  1.4523 +  // Convert the index to a size_t and bounds-check it.
  1.4524 +  size_t index;
  1.4525 +  size_t length = GetLength(typeObj);
  1.4526 +  bool ok = jsidToSize(cx, idval, true, &index);
  1.4527 +  int32_t dummy;
  1.4528 +  if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
  1.4529 +    // String either isn't a number, or doesn't fit in size_t.
  1.4530 +    // Chances are it's a regular property lookup, so return.
  1.4531 +    return true;
  1.4532 +  }
  1.4533 +  if (!ok || index >= length) {
  1.4534 +    JS_ReportError(cx, "invalid index");
  1.4535 +    return false;
  1.4536 +  }
  1.4537 +
  1.4538 +  RootedObject baseType(cx, GetBaseType(typeObj));
  1.4539 +  size_t elementSize = CType::GetSize(baseType);
  1.4540 +  char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  1.4541 +  return ConvertToJS(cx, baseType, obj, data, false, false, vp.address());
  1.4542 +}
  1.4543 +
  1.4544 +bool
  1.4545 +ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
  1.4546 +{
  1.4547 +  // This should never happen, but we'll check to be safe.
  1.4548 +  if (!CData::IsCData(obj)) {
  1.4549 +    JS_ReportError(cx, "not a CData");
  1.4550 +    return false;
  1.4551 +  }
  1.4552 +
  1.4553 +  // Bail early if we're not an ArrayType. (This setter is present for all
  1.4554 +  // CData, regardless of CType.)
  1.4555 +  JSObject* typeObj = CData::GetCType(obj);
  1.4556 +  if (CType::GetTypeCode(typeObj) != TYPE_array)
  1.4557 +    return true;
  1.4558 +
  1.4559 +  // Convert the index to a size_t and bounds-check it.
  1.4560 +  size_t index;
  1.4561 +  size_t length = GetLength(typeObj);
  1.4562 +  bool ok = jsidToSize(cx, idval, true, &index);
  1.4563 +  int32_t dummy;
  1.4564 +  if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
  1.4565 +    // String either isn't a number, or doesn't fit in size_t.
  1.4566 +    // Chances are it's a regular property lookup, so return.
  1.4567 +    return true;
  1.4568 +  }
  1.4569 +  if (!ok || index >= length) {
  1.4570 +    JS_ReportError(cx, "invalid index");
  1.4571 +    return false;
  1.4572 +  }
  1.4573 +
  1.4574 +  JSObject* baseType = GetBaseType(typeObj);
  1.4575 +  size_t elementSize = CType::GetSize(baseType);
  1.4576 +  char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  1.4577 +  return ImplicitConvert(cx, vp, baseType, data, false, nullptr);
  1.4578 +}
  1.4579 +
  1.4580 +bool
  1.4581 +ArrayType::AddressOfElement(JSContext* cx, unsigned argc, jsval* vp)
  1.4582 +{
  1.4583 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4584 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.4585 +  if (!obj)
  1.4586 +    return false;
  1.4587 +  if (!CData::IsCData(obj)) {
  1.4588 +    JS_ReportError(cx, "not a CData");
  1.4589 +    return false;
  1.4590 +  }
  1.4591 +
  1.4592 +  RootedObject typeObj(cx, CData::GetCType(obj));
  1.4593 +  if (CType::GetTypeCode(typeObj) != TYPE_array) {
  1.4594 +    JS_ReportError(cx, "not an ArrayType");
  1.4595 +    return false;
  1.4596 +  }
  1.4597 +
  1.4598 +  if (args.length() != 1) {
  1.4599 +    JS_ReportError(cx, "addressOfElement takes one argument");
  1.4600 +    return false;
  1.4601 +  }
  1.4602 +
  1.4603 +  RootedObject baseType(cx, GetBaseType(typeObj));
  1.4604 +  RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
  1.4605 +  if (!pointerType)
  1.4606 +    return false;
  1.4607 +
  1.4608 +  // Create a PointerType CData object containing null.
  1.4609 +  RootedObject result(cx, CData::Create(cx, pointerType, NullPtr(), nullptr, true));
  1.4610 +  if (!result)
  1.4611 +    return false;
  1.4612 +
  1.4613 +  args.rval().setObject(*result);
  1.4614 +
  1.4615 +  // Convert the index to a size_t and bounds-check it.
  1.4616 +  size_t index;
  1.4617 +  size_t length = GetLength(typeObj);
  1.4618 +  if (!jsvalToSize(cx, args[0], false, &index) ||
  1.4619 +      index >= length) {
  1.4620 +    JS_ReportError(cx, "invalid index");
  1.4621 +    return false;
  1.4622 +  }
  1.4623 +
  1.4624 +  // Manually set the pointer inside the object, so we skip the conversion step.
  1.4625 +  void** data = static_cast<void**>(CData::GetData(result));
  1.4626 +  size_t elementSize = CType::GetSize(baseType);
  1.4627 +  *data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  1.4628 +  return true;
  1.4629 +}
  1.4630 +
  1.4631 +/*******************************************************************************
  1.4632 +** StructType implementation
  1.4633 +*******************************************************************************/
  1.4634 +
  1.4635 +// For a struct field descriptor 'val' of the form { name : type }, extract
  1.4636 +// 'name' and 'type'.
  1.4637 +static JSFlatString*
  1.4638 +ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
  1.4639 +{
  1.4640 +  if (JSVAL_IS_PRIMITIVE(val)) {
  1.4641 +    JS_ReportError(cx, "struct field descriptors require a valid name and type");
  1.4642 +    return nullptr;
  1.4643 +  }
  1.4644 +
  1.4645 +  RootedObject obj(cx, JSVAL_TO_OBJECT(val));
  1.4646 +  RootedObject iter(cx, JS_NewPropertyIterator(cx, obj));
  1.4647 +  if (!iter)
  1.4648 +    return nullptr;
  1.4649 +
  1.4650 +  RootedId nameid(cx);
  1.4651 +  if (!JS_NextProperty(cx, iter, nameid.address()))
  1.4652 +    return nullptr;
  1.4653 +  if (JSID_IS_VOID(nameid)) {
  1.4654 +    JS_ReportError(cx, "struct field descriptors require a valid name and type");
  1.4655 +    return nullptr;
  1.4656 +  }
  1.4657 +
  1.4658 +  if (!JSID_IS_STRING(nameid)) {
  1.4659 +    JS_ReportError(cx, "struct field descriptors require a valid name and type");
  1.4660 +    return nullptr;
  1.4661 +  }
  1.4662 +
  1.4663 +  // make sure we have one, and only one, property
  1.4664 +  jsid id;
  1.4665 +  if (!JS_NextProperty(cx, iter, &id))
  1.4666 +    return nullptr;
  1.4667 +  if (!JSID_IS_VOID(id)) {
  1.4668 +    JS_ReportError(cx, "struct field descriptors must contain one property");
  1.4669 +    return nullptr;
  1.4670 +  }
  1.4671 +
  1.4672 +  RootedValue propVal(cx);
  1.4673 +  if (!JS_GetPropertyById(cx, obj, nameid, &propVal))
  1.4674 +    return nullptr;
  1.4675 +
  1.4676 +  if (propVal.isPrimitive() || !CType::IsCType(&propVal.toObject())) {
  1.4677 +    JS_ReportError(cx, "struct field descriptors require a valid name and type");
  1.4678 +    return nullptr;
  1.4679 +  }
  1.4680 +
  1.4681 +  // Undefined size or zero size struct members are illegal.
  1.4682 +  // (Zero-size arrays are legal as struct members in C++, but libffi will
  1.4683 +  // choke on a zero-size struct, so we disallow them.)
  1.4684 +  *typeObj = &propVal.toObject();
  1.4685 +  size_t size;
  1.4686 +  if (!CType::GetSafeSize(*typeObj, &size) || size == 0) {
  1.4687 +    JS_ReportError(cx, "struct field types must have defined and nonzero size");
  1.4688 +    return nullptr;
  1.4689 +  }
  1.4690 +
  1.4691 +  return JSID_TO_FLAT_STRING(nameid);
  1.4692 +}
  1.4693 +
  1.4694 +// For a struct field with 'name' and 'type', add an element of the form
  1.4695 +// { name : type }.
  1.4696 +static bool
  1.4697 +AddFieldToArray(JSContext* cx,
  1.4698 +                jsval* element,
  1.4699 +                JSFlatString* name_,
  1.4700 +                JSObject* typeObj_)
  1.4701 +{
  1.4702 +  RootedObject typeObj(cx, typeObj_);
  1.4703 +  Rooted<JSFlatString*> name(cx, name_);
  1.4704 +  RootedObject fieldObj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
  1.4705 +  if (!fieldObj)
  1.4706 +    return false;
  1.4707 +
  1.4708 +  *element = OBJECT_TO_JSVAL(fieldObj);
  1.4709 +
  1.4710 +  if (!JS_DefineUCProperty(cx, fieldObj,
  1.4711 +         name->chars(), name->length(),
  1.4712 +         OBJECT_TO_JSVAL(typeObj), nullptr, nullptr,
  1.4713 +         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1.4714 +    return false;
  1.4715 +
  1.4716 +  return JS_FreezeObject(cx, fieldObj);
  1.4717 +}
  1.4718 +
  1.4719 +bool
  1.4720 +StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
  1.4721 +{
  1.4722 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4723 +
  1.4724 +  // Construct and return a new StructType object.
  1.4725 +  if (args.length() < 1 || args.length() > 2) {
  1.4726 +    JS_ReportError(cx, "StructType takes one or two arguments");
  1.4727 +    return false;
  1.4728 +  }
  1.4729 +
  1.4730 +  jsval name = args[0];
  1.4731 +  if (!name.isString()) {
  1.4732 +    JS_ReportError(cx, "first argument must be a string");
  1.4733 +    return false;
  1.4734 +  }
  1.4735 +
  1.4736 +  // Get ctypes.StructType.prototype from the ctypes.StructType constructor.
  1.4737 +  RootedObject typeProto(cx, CType::GetProtoFromCtor(&args.callee(), SLOT_STRUCTPROTO));
  1.4738 +
  1.4739 +  // Create a simple StructType with no defined fields. The result will be
  1.4740 +  // non-instantiable as CData, will have no 'prototype' property, and will
  1.4741 +  // have undefined size and alignment and no ffi_type.
  1.4742 +  RootedObject result(cx, CType::Create(cx, typeProto, NullPtr(), TYPE_struct,
  1.4743 +                                        JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, nullptr));
  1.4744 +  if (!result)
  1.4745 +    return false;
  1.4746 +
  1.4747 +  if (args.length() == 2) {
  1.4748 +    RootedObject arr(cx, JSVAL_IS_PRIMITIVE(args[1]) ? nullptr : &args[1].toObject());
  1.4749 +    if (!arr || !JS_IsArrayObject(cx, arr)) {
  1.4750 +      JS_ReportError(cx, "second argument must be an array");
  1.4751 +      return false;
  1.4752 +    }
  1.4753 +
  1.4754 +    // Define the struct fields.
  1.4755 +    if (!DefineInternal(cx, result, arr))
  1.4756 +      return false;
  1.4757 +  }
  1.4758 +
  1.4759 +  args.rval().setObject(*result);
  1.4760 +  return true;
  1.4761 +}
  1.4762 +
  1.4763 +static void
  1.4764 +PostBarrierCallback(JSTracer *trc, JSString *key, void *data)
  1.4765 +{
  1.4766 +    typedef HashMap<JSFlatString*,
  1.4767 +                    UnbarrieredFieldInfo,
  1.4768 +                    FieldHashPolicy,
  1.4769 +                    SystemAllocPolicy> UnbarrieredFieldInfoHash;
  1.4770 +
  1.4771 +    UnbarrieredFieldInfoHash *table = reinterpret_cast<UnbarrieredFieldInfoHash*>(data);
  1.4772 +    JSString *prior = key;
  1.4773 +    JS_CallStringTracer(trc, &key, "CType fieldName");
  1.4774 +    table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
  1.4775 +}
  1.4776 +
  1.4777 +bool
  1.4778 +StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsObj_)
  1.4779 +{
  1.4780 +  RootedObject typeObj(cx, typeObj_);
  1.4781 +  RootedObject fieldsObj(cx, fieldsObj_);
  1.4782 +
  1.4783 +  uint32_t len;
  1.4784 +  ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len));
  1.4785 +
  1.4786 +  // Get the common prototype for CData objects of this type from
  1.4787 +  // ctypes.CType.prototype.
  1.4788 +  RootedObject dataProto(cx, CType::GetProtoFromType(cx, typeObj, SLOT_STRUCTDATAPROTO));
  1.4789 +  if (!dataProto)
  1.4790 +    return false;
  1.4791 +
  1.4792 +  // Set up the 'prototype' and 'prototype.constructor' properties.
  1.4793 +  // The prototype will reflect the struct fields as properties on CData objects
  1.4794 +  // created from this type.
  1.4795 +  RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, NullPtr()));
  1.4796 +  if (!prototype)
  1.4797 +    return false;
  1.4798 +
  1.4799 +  if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
  1.4800 +                         JSPROP_READONLY | JSPROP_PERMANENT))
  1.4801 +    return false;
  1.4802 +
  1.4803 +  // Create a FieldInfoHash to stash on the type object, and an array to root
  1.4804 +  // its constituents. (We cannot simply stash the hash in a reserved slot now
  1.4805 +  // to get GC safety for free, since if anything in this function fails we
  1.4806 +  // do not want to mutate 'typeObj'.)
  1.4807 +  AutoPtr<FieldInfoHash> fields(cx->new_<FieldInfoHash>());
  1.4808 +  if (!fields || !fields->init(len)) {
  1.4809 +    JS_ReportOutOfMemory(cx);
  1.4810 +    return false;
  1.4811 +  }
  1.4812 +  JS::AutoValueVector fieldRoots(cx);
  1.4813 +  if (!fieldRoots.resize(len)) {
  1.4814 +    JS_ReportOutOfMemory(cx);
  1.4815 +    return false;
  1.4816 +  }
  1.4817 +
  1.4818 +  // Process the field types.
  1.4819 +  size_t structSize, structAlign;
  1.4820 +  if (len != 0) {
  1.4821 +    structSize = 0;
  1.4822 +    structAlign = 0;
  1.4823 +
  1.4824 +    for (uint32_t i = 0; i < len; ++i) {
  1.4825 +      RootedValue item(cx);
  1.4826 +      if (!JS_GetElement(cx, fieldsObj, i, &item))
  1.4827 +        return false;
  1.4828 +
  1.4829 +      RootedObject fieldType(cx, nullptr);
  1.4830 +      Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, fieldType.address()));
  1.4831 +      if (!name)
  1.4832 +        return false;
  1.4833 +      fieldRoots[i] = JS::ObjectValue(*fieldType);
  1.4834 +
  1.4835 +      // Make sure each field name is unique
  1.4836 +      FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
  1.4837 +      if (entryPtr) {
  1.4838 +        JS_ReportError(cx, "struct fields must have unique names");
  1.4839 +        return false;
  1.4840 +      }
  1.4841 +
  1.4842 +      // Add the field to the StructType's 'prototype' property.
  1.4843 +      if (!JS_DefineUCProperty(cx, prototype,
  1.4844 +             name->chars(), name->length(), JSVAL_VOID,
  1.4845 +             StructType::FieldGetter, StructType::FieldSetter,
  1.4846 +             JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT))
  1.4847 +        return false;
  1.4848 +
  1.4849 +      size_t fieldSize = CType::GetSize(fieldType);
  1.4850 +      size_t fieldAlign = CType::GetAlignment(fieldType);
  1.4851 +      size_t fieldOffset = Align(structSize, fieldAlign);
  1.4852 +      // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
  1.4853 +      // be zero, we can safely check fieldOffset + fieldSize without first
  1.4854 +      // checking fieldOffset for overflow.
  1.4855 +      if (fieldOffset + fieldSize < structSize) {
  1.4856 +        JS_ReportError(cx, "size overflow");
  1.4857 +        return false;
  1.4858 +      }
  1.4859 +
  1.4860 +      // Add field name to the hash
  1.4861 +      FieldInfo info;
  1.4862 +      info.mType = fieldType;
  1.4863 +      info.mIndex = i;
  1.4864 +      info.mOffset = fieldOffset;
  1.4865 +      ASSERT_OK(fields->add(entryPtr, name, info));
  1.4866 +      JS_StoreStringPostBarrierCallback(cx, PostBarrierCallback, name, fields.get());
  1.4867 +
  1.4868 +      structSize = fieldOffset + fieldSize;
  1.4869 +
  1.4870 +      if (fieldAlign > structAlign)
  1.4871 +        structAlign = fieldAlign;
  1.4872 +    }
  1.4873 +
  1.4874 +    // Pad the struct tail according to struct alignment.
  1.4875 +    size_t structTail = Align(structSize, structAlign);
  1.4876 +    if (structTail < structSize) {
  1.4877 +      JS_ReportError(cx, "size overflow");
  1.4878 +      return false;
  1.4879 +    }
  1.4880 +    structSize = structTail;
  1.4881 +
  1.4882 +  } else {
  1.4883 +    // Empty structs are illegal in C, but are legal and have a size of
  1.4884 +    // 1 byte in C++. We're going to allow them, and trick libffi into
  1.4885 +    // believing this by adding a char member. The resulting struct will have
  1.4886 +    // no getters or setters, and will be initialized to zero.
  1.4887 +    structSize = 1;
  1.4888 +    structAlign = 1;
  1.4889 +  }
  1.4890 +
  1.4891 +  RootedValue sizeVal(cx);
  1.4892 +  if (!SizeTojsval(cx, structSize, sizeVal.address()))
  1.4893 +    return false;
  1.4894 +
  1.4895 +  JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PRIVATE_TO_JSVAL(fields.forget()));
  1.4896 +
  1.4897 +  JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
  1.4898 +  JS_SetReservedSlot(typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign));
  1.4899 +  //if (!JS_FreezeObject(cx, prototype)0 // XXX fixme - see bug 541212!
  1.4900 +  //  return false;
  1.4901 +  JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
  1.4902 +  return true;
  1.4903 +}
  1.4904 +
  1.4905 +ffi_type*
  1.4906 +StructType::BuildFFIType(JSContext* cx, JSObject* obj)
  1.4907 +{
  1.4908 +  JS_ASSERT(CType::IsCType(obj));
  1.4909 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  1.4910 +  JS_ASSERT(CType::IsSizeDefined(obj));
  1.4911 +
  1.4912 +  const FieldInfoHash* fields = GetFieldInfo(obj);
  1.4913 +  size_t len = fields->count();
  1.4914 +
  1.4915 +  size_t structSize = CType::GetSize(obj);
  1.4916 +  size_t structAlign = CType::GetAlignment(obj);
  1.4917 +
  1.4918 +  AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
  1.4919 +  if (!ffiType) {
  1.4920 +    JS_ReportOutOfMemory(cx);
  1.4921 +    return nullptr;
  1.4922 +  }
  1.4923 +  ffiType->type = FFI_TYPE_STRUCT;
  1.4924 +
  1.4925 +  AutoPtr<ffi_type*> elements;
  1.4926 +  if (len != 0) {
  1.4927 +    elements = cx->pod_malloc<ffi_type*>(len + 1);
  1.4928 +    if (!elements) {
  1.4929 +      JS_ReportOutOfMemory(cx);
  1.4930 +      return nullptr;
  1.4931 +    }
  1.4932 +    elements[len] = nullptr;
  1.4933 +
  1.4934 +    for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  1.4935 +      const FieldInfoHash::Entry& entry = r.front();
  1.4936 +      ffi_type* fieldType = CType::GetFFIType(cx, entry.value().mType);
  1.4937 +      if (!fieldType)
  1.4938 +        return nullptr;
  1.4939 +      elements[entry.value().mIndex] = fieldType;
  1.4940 +    }
  1.4941 +
  1.4942 +  } else {
  1.4943 +    // Represent an empty struct as having a size of 1 byte, just like C++.
  1.4944 +    JS_ASSERT(structSize == 1);
  1.4945 +    JS_ASSERT(structAlign == 1);
  1.4946 +    elements = cx->pod_malloc<ffi_type*>(2);
  1.4947 +    if (!elements) {
  1.4948 +      JS_ReportOutOfMemory(cx);
  1.4949 +      return nullptr;
  1.4950 +    }
  1.4951 +    elements[0] = &ffi_type_uint8;
  1.4952 +    elements[1] = nullptr;
  1.4953 +  }
  1.4954 +
  1.4955 +  ffiType->elements = elements.get();
  1.4956 +
  1.4957 +#ifdef DEBUG
  1.4958 +  // Perform a sanity check: the result of our struct size and alignment
  1.4959 +  // calculations should match libffi's. We force it to do this calculation
  1.4960 +  // by calling ffi_prep_cif.
  1.4961 +  ffi_cif cif;
  1.4962 +  ffiType->size = 0;
  1.4963 +  ffiType->alignment = 0;
  1.4964 +  ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), nullptr);
  1.4965 +  JS_ASSERT(status == FFI_OK);
  1.4966 +  JS_ASSERT(structSize == ffiType->size);
  1.4967 +  JS_ASSERT(structAlign == ffiType->alignment);
  1.4968 +#else
  1.4969 +  // Fill in the ffi_type's size and align fields. This makes libffi treat the
  1.4970 +  // type as initialized; it will not recompute the values. (We assume
  1.4971 +  // everything agrees; if it doesn't, we really want to know about it, which
  1.4972 +  // is the purpose of the above debug-only check.)
  1.4973 +  ffiType->size = structSize;
  1.4974 +  ffiType->alignment = structAlign;
  1.4975 +#endif
  1.4976 +
  1.4977 +  elements.forget();
  1.4978 +  return ffiType.forget();
  1.4979 +}
  1.4980 +
  1.4981 +bool
  1.4982 +StructType::Define(JSContext* cx, unsigned argc, jsval* vp)
  1.4983 +{
  1.4984 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.4985 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.4986 +  if (!obj)
  1.4987 +    return false;
  1.4988 +  if (!CType::IsCType(obj) ||
  1.4989 +      CType::GetTypeCode(obj) != TYPE_struct) {
  1.4990 +    JS_ReportError(cx, "not a StructType");
  1.4991 +    return false;
  1.4992 +  }
  1.4993 +
  1.4994 +  if (CType::IsSizeDefined(obj)) {
  1.4995 +    JS_ReportError(cx, "StructType has already been defined");
  1.4996 +    return false;
  1.4997 +  }
  1.4998 +
  1.4999 +  if (args.length() != 1) {
  1.5000 +    JS_ReportError(cx, "define takes one argument");
  1.5001 +    return false;
  1.5002 +  }
  1.5003 +
  1.5004 +  jsval arg = args[0];
  1.5005 +  if (JSVAL_IS_PRIMITIVE(arg)) {
  1.5006 +    JS_ReportError(cx, "argument must be an array");
  1.5007 +    return false;
  1.5008 +  }
  1.5009 +  RootedObject arr(cx, JSVAL_TO_OBJECT(arg));
  1.5010 +  if (!JS_IsArrayObject(cx, arr)) {
  1.5011 +    JS_ReportError(cx, "argument must be an array");
  1.5012 +    return false;
  1.5013 +  }
  1.5014 +
  1.5015 +  return DefineInternal(cx, obj, arr);
  1.5016 +}
  1.5017 +
  1.5018 +bool
  1.5019 +StructType::ConstructData(JSContext* cx,
  1.5020 +                          HandleObject obj,
  1.5021 +                          const CallArgs& args)
  1.5022 +{
  1.5023 +  if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_struct) {
  1.5024 +    JS_ReportError(cx, "not a StructType");
  1.5025 +    return false;
  1.5026 +  }
  1.5027 +
  1.5028 +  if (!CType::IsSizeDefined(obj)) {
  1.5029 +    JS_ReportError(cx, "cannot construct an opaque StructType");
  1.5030 +    return false;
  1.5031 +  }
  1.5032 +
  1.5033 +  JSObject* result = CData::Create(cx, obj, NullPtr(), nullptr, true);
  1.5034 +  if (!result)
  1.5035 +    return false;
  1.5036 +
  1.5037 +  args.rval().setObject(*result);
  1.5038 +
  1.5039 +  if (args.length() == 0)
  1.5040 +    return true;
  1.5041 +
  1.5042 +  char* buffer = static_cast<char*>(CData::GetData(result));
  1.5043 +  const FieldInfoHash* fields = GetFieldInfo(obj);
  1.5044 +
  1.5045 +  if (args.length() == 1) {
  1.5046 +    // There are two possible interpretations of the argument:
  1.5047 +    // 1) It may be an object '{ ... }' with properties representing the
  1.5048 +    //    struct fields intended to ExplicitConvert wholesale to our StructType.
  1.5049 +    // 2) If the struct contains one field, the arg may be intended to
  1.5050 +    //    ImplicitConvert directly to that arg's CType.
  1.5051 +    // Thankfully, the conditions for these two possibilities to succeed
  1.5052 +    // are mutually exclusive, so we can pick the right one.
  1.5053 +
  1.5054 +    // Try option 1) first.
  1.5055 +    if (ExplicitConvert(cx, args[0], obj, buffer))
  1.5056 +      return true;
  1.5057 +
  1.5058 +    if (fields->count() != 1)
  1.5059 +      return false;
  1.5060 +
  1.5061 +    // If ExplicitConvert failed, and there is no pending exception, then assume
  1.5062 +    // hard failure (out of memory, or some other similarly serious condition).
  1.5063 +    if (!JS_IsExceptionPending(cx))
  1.5064 +      return false;
  1.5065 +
  1.5066 +    // Otherwise, assume soft failure, and clear the pending exception so that we
  1.5067 +    // can throw a different one as required.
  1.5068 +    JS_ClearPendingException(cx);
  1.5069 +
  1.5070 +    // Fall through to try option 2).
  1.5071 +  }
  1.5072 +
  1.5073 +  // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'.
  1.5074 +  // ImplicitConvert each field.
  1.5075 +  if (args.length() == fields->count()) {
  1.5076 +    for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  1.5077 +      const FieldInfo& field = r.front().value();
  1.5078 +      STATIC_ASSUME(field.mIndex < fields->count());  /* Quantified invariant */
  1.5079 +      if (!ImplicitConvert(cx, args[field.mIndex], field.mType,
  1.5080 +             buffer + field.mOffset,
  1.5081 +             false, nullptr))
  1.5082 +        return false;
  1.5083 +    }
  1.5084 +
  1.5085 +    return true;
  1.5086 +  }
  1.5087 +
  1.5088 +  JS_ReportError(cx, "constructor takes 0, 1, or %u arguments",
  1.5089 +    fields->count());
  1.5090 +  return false;
  1.5091 +}
  1.5092 +
  1.5093 +const FieldInfoHash*
  1.5094 +StructType::GetFieldInfo(JSObject* obj)
  1.5095 +{
  1.5096 +  JS_ASSERT(CType::IsCType(obj));
  1.5097 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  1.5098 +
  1.5099 +  jsval slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
  1.5100 +  JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
  1.5101 +
  1.5102 +  return static_cast<const FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
  1.5103 +}
  1.5104 +
  1.5105 +const FieldInfo*
  1.5106 +StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
  1.5107 +{
  1.5108 +  JS_ASSERT(CType::IsCType(obj));
  1.5109 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  1.5110 +
  1.5111 +  FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name);
  1.5112 +  if (ptr)
  1.5113 +    return &ptr->value();
  1.5114 +
  1.5115 +  JSAutoByteString bytes(cx, name);
  1.5116 +  if (!bytes)
  1.5117 +    return nullptr;
  1.5118 +
  1.5119 +  JS_ReportError(cx, "%s does not name a field", bytes.ptr());
  1.5120 +  return nullptr;
  1.5121 +}
  1.5122 +
  1.5123 +JSObject*
  1.5124 +StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
  1.5125 +{
  1.5126 +  JS_ASSERT(CType::IsCType(obj));
  1.5127 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  1.5128 +  JS_ASSERT(CType::IsSizeDefined(obj));
  1.5129 +
  1.5130 +  const FieldInfoHash* fields = GetFieldInfo(obj);
  1.5131 +  size_t len = fields->count();
  1.5132 +
  1.5133 +  // Prepare a new array for the 'fields' property of the StructType.
  1.5134 +  JS::AutoValueVector fieldsVec(cx);
  1.5135 +  if (!fieldsVec.resize(len))
  1.5136 +    return nullptr;
  1.5137 +
  1.5138 +  for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  1.5139 +    const FieldInfoHash::Entry& entry = r.front();
  1.5140 +    // Add the field descriptor to the array.
  1.5141 +    if (!AddFieldToArray(cx, &fieldsVec[entry.value().mIndex],
  1.5142 +                         entry.key(), entry.value().mType))
  1.5143 +      return nullptr;
  1.5144 +  }
  1.5145 +
  1.5146 +  RootedObject fieldsProp(cx, JS_NewArrayObject(cx, fieldsVec));
  1.5147 +  if (!fieldsProp)
  1.5148 +    return nullptr;
  1.5149 +
  1.5150 +  // Seal the fields array.
  1.5151 +  if (!JS_FreezeObject(cx, fieldsProp))
  1.5152 +    return nullptr;
  1.5153 +
  1.5154 +  return fieldsProp;
  1.5155 +}
  1.5156 +
  1.5157 +/* static */ bool
  1.5158 +StructType::IsStruct(HandleValue v)
  1.5159 +{
  1.5160 +  if (!v.isObject())
  1.5161 +    return false;
  1.5162 +  JSObject* obj = &v.toObject();
  1.5163 +  return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_struct;
  1.5164 +}
  1.5165 +
  1.5166 +bool
  1.5167 +StructType::FieldsArrayGetter(JSContext* cx, JS::CallArgs args)
  1.5168 +{
  1.5169 +  RootedObject obj(cx, &args.thisv().toObject());
  1.5170 +
  1.5171 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_FIELDS));
  1.5172 +
  1.5173 +  if (!CType::IsSizeDefined(obj)) {
  1.5174 +    MOZ_ASSERT(args.rval().isUndefined());
  1.5175 +    return true;
  1.5176 +  }
  1.5177 +
  1.5178 +  if (args.rval().isUndefined()) {
  1.5179 +    // Build the 'fields' array lazily.
  1.5180 +    JSObject* fields = BuildFieldsArray(cx, obj);
  1.5181 +    if (!fields)
  1.5182 +      return false;
  1.5183 +    JS_SetReservedSlot(obj, SLOT_FIELDS, OBJECT_TO_JSVAL(fields));
  1.5184 +
  1.5185 +    args.rval().setObject(*fields);
  1.5186 +  }
  1.5187 +
  1.5188 +  MOZ_ASSERT(args.rval().isObject());
  1.5189 +  MOZ_ASSERT(JS_IsArrayObject(cx, args.rval()));
  1.5190 +  return true;
  1.5191 +}
  1.5192 +
  1.5193 +bool
  1.5194 +StructType::FieldGetter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp)
  1.5195 +{
  1.5196 +  if (!CData::IsCData(obj)) {
  1.5197 +    JS_ReportError(cx, "not a CData");
  1.5198 +    return false;
  1.5199 +  }
  1.5200 +
  1.5201 +  JSObject* typeObj = CData::GetCType(obj);
  1.5202 +  if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  1.5203 +    JS_ReportError(cx, "not a StructType");
  1.5204 +    return false;
  1.5205 +  }
  1.5206 +
  1.5207 +  const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
  1.5208 +  if (!field)
  1.5209 +    return false;
  1.5210 +
  1.5211 +  char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  1.5212 +  RootedObject fieldType(cx, field->mType);
  1.5213 +  return ConvertToJS(cx, fieldType, obj, data, false, false, vp.address());
  1.5214 +}
  1.5215 +
  1.5216 +bool
  1.5217 +StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
  1.5218 +{
  1.5219 +  if (!CData::IsCData(obj)) {
  1.5220 +    JS_ReportError(cx, "not a CData");
  1.5221 +    return false;
  1.5222 +  }
  1.5223 +
  1.5224 +  JSObject* typeObj = CData::GetCType(obj);
  1.5225 +  if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  1.5226 +    JS_ReportError(cx, "not a StructType");
  1.5227 +    return false;
  1.5228 +  }
  1.5229 +
  1.5230 +  const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
  1.5231 +  if (!field)
  1.5232 +    return false;
  1.5233 +
  1.5234 +  char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  1.5235 +  return ImplicitConvert(cx, vp, field->mType, data, false, nullptr);
  1.5236 +}
  1.5237 +
  1.5238 +bool
  1.5239 +StructType::AddressOfField(JSContext* cx, unsigned argc, jsval* vp)
  1.5240 +{
  1.5241 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.5242 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.5243 +  if (!obj)
  1.5244 +    return false;
  1.5245 +  if (!CData::IsCData(obj)) {
  1.5246 +    JS_ReportError(cx, "not a CData");
  1.5247 +    return false;
  1.5248 +  }
  1.5249 +
  1.5250 +  JSObject* typeObj = CData::GetCType(obj);
  1.5251 +  if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  1.5252 +    JS_ReportError(cx, "not a StructType");
  1.5253 +    return false;
  1.5254 +  }
  1.5255 +
  1.5256 +  if (args.length() != 1) {
  1.5257 +    JS_ReportError(cx, "addressOfField takes one argument");
  1.5258 +    return false;
  1.5259 +  }
  1.5260 +
  1.5261 +  JSFlatString *str = JS_FlattenString(cx, args[0].toString());
  1.5262 +  if (!str)
  1.5263 +    return false;
  1.5264 +
  1.5265 +  const FieldInfo* field = LookupField(cx, typeObj, str);
  1.5266 +  if (!field)
  1.5267 +    return false;
  1.5268 +
  1.5269 +  RootedObject baseType(cx, field->mType);
  1.5270 +  RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
  1.5271 +  if (!pointerType)
  1.5272 +    return false;
  1.5273 +
  1.5274 +  // Create a PointerType CData object containing null.
  1.5275 +  JSObject* result = CData::Create(cx, pointerType, NullPtr(), nullptr, true);
  1.5276 +  if (!result)
  1.5277 +    return false;
  1.5278 +
  1.5279 +  args.rval().setObject(*result);
  1.5280 +
  1.5281 +  // Manually set the pointer inside the object, so we skip the conversion step.
  1.5282 +  void** data = static_cast<void**>(CData::GetData(result));
  1.5283 +  *data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  1.5284 +  return true;
  1.5285 +}
  1.5286 +
  1.5287 +/*******************************************************************************
  1.5288 +** FunctionType implementation
  1.5289 +*******************************************************************************/
  1.5290 +
  1.5291 +// Helper class for handling allocation of function arguments.
  1.5292 +struct AutoValue
  1.5293 +{
  1.5294 +  AutoValue() : mData(nullptr) { }
  1.5295 +
  1.5296 +  ~AutoValue()
  1.5297 +  {
  1.5298 +    js_free(mData);
  1.5299 +  }
  1.5300 +
  1.5301 +  bool SizeToType(JSContext* cx, JSObject* type)
  1.5302 +  {
  1.5303 +    // Allocate a minimum of sizeof(ffi_arg) to handle small integers.
  1.5304 +    size_t size = Align(CType::GetSize(type), sizeof(ffi_arg));
  1.5305 +    mData = js_malloc(size);
  1.5306 +    if (mData)
  1.5307 +      memset(mData, 0, size);
  1.5308 +    return mData != nullptr;
  1.5309 +  }
  1.5310 +
  1.5311 +  void* mData;
  1.5312 +};
  1.5313 +
  1.5314 +static bool
  1.5315 +GetABI(JSContext* cx, jsval abiType, ffi_abi* result)
  1.5316 +{
  1.5317 +  if (JSVAL_IS_PRIMITIVE(abiType))
  1.5318 +    return false;
  1.5319 +
  1.5320 +  ABICode abi = GetABICode(JSVAL_TO_OBJECT(abiType));
  1.5321 +
  1.5322 +  // determine the ABI from the subset of those available on the
  1.5323 +  // given platform. ABI_DEFAULT specifies the default
  1.5324 +  // C calling convention (cdecl) on each platform.
  1.5325 +  switch (abi) {
  1.5326 +  case ABI_DEFAULT:
  1.5327 +    *result = FFI_DEFAULT_ABI;
  1.5328 +    return true;
  1.5329 +  case ABI_STDCALL:
  1.5330 +  case ABI_WINAPI:
  1.5331 +#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
  1.5332 +    *result = FFI_STDCALL;
  1.5333 +    return true;
  1.5334 +#elif (defined(_WIN64))
  1.5335 +    // We'd like the same code to work across Win32 and Win64, so stdcall_api
  1.5336 +    // and winapi_abi become aliases to the lone Win64 ABI.
  1.5337 +    *result = FFI_WIN64;
  1.5338 +    return true;
  1.5339 +#endif
  1.5340 +  case INVALID_ABI:
  1.5341 +    break;
  1.5342 +  }
  1.5343 +  return false;
  1.5344 +}
  1.5345 +
  1.5346 +static JSObject*
  1.5347 +PrepareType(JSContext* cx, jsval type)
  1.5348 +{
  1.5349 +  if (JSVAL_IS_PRIMITIVE(type) ||
  1.5350 +      !CType::IsCType(JSVAL_TO_OBJECT(type))) {
  1.5351 +    JS_ReportError(cx, "not a ctypes type");
  1.5352 +    return nullptr;
  1.5353 +  }
  1.5354 +
  1.5355 +  JSObject* result = JSVAL_TO_OBJECT(type);
  1.5356 +  TypeCode typeCode = CType::GetTypeCode(result);
  1.5357 +
  1.5358 +  if (typeCode == TYPE_array) {
  1.5359 +    // convert array argument types to pointers, just like C.
  1.5360 +    // ImplicitConvert will do the same, when passing an array as data.
  1.5361 +    RootedObject baseType(cx, ArrayType::GetBaseType(result));
  1.5362 +    result = PointerType::CreateInternal(cx, baseType);
  1.5363 +    if (!result)
  1.5364 +      return nullptr;
  1.5365 +
  1.5366 +  } else if (typeCode == TYPE_void_t || typeCode == TYPE_function) {
  1.5367 +    // disallow void or function argument types
  1.5368 +    JS_ReportError(cx, "Cannot have void or function argument type");
  1.5369 +    return nullptr;
  1.5370 +  }
  1.5371 +
  1.5372 +  if (!CType::IsSizeDefined(result)) {
  1.5373 +    JS_ReportError(cx, "Argument type must have defined size");
  1.5374 +    return nullptr;
  1.5375 +  }
  1.5376 +
  1.5377 +  // libffi cannot pass types of zero size by value.
  1.5378 +  JS_ASSERT(CType::GetSize(result) != 0);
  1.5379 +
  1.5380 +  return result;
  1.5381 +}
  1.5382 +
  1.5383 +static JSObject*
  1.5384 +PrepareReturnType(JSContext* cx, jsval type)
  1.5385 +{
  1.5386 +  if (JSVAL_IS_PRIMITIVE(type) ||
  1.5387 +      !CType::IsCType(JSVAL_TO_OBJECT(type))) {
  1.5388 +    JS_ReportError(cx, "not a ctypes type");
  1.5389 +    return nullptr;
  1.5390 +  }
  1.5391 +
  1.5392 +  JSObject* result = JSVAL_TO_OBJECT(type);
  1.5393 +  TypeCode typeCode = CType::GetTypeCode(result);
  1.5394 +
  1.5395 +  // Arrays and functions can never be return types.
  1.5396 +  if (typeCode == TYPE_array || typeCode == TYPE_function) {
  1.5397 +    JS_ReportError(cx, "Return type cannot be an array or function");
  1.5398 +    return nullptr;
  1.5399 +  }
  1.5400 +
  1.5401 +  if (typeCode != TYPE_void_t && !CType::IsSizeDefined(result)) {
  1.5402 +    JS_ReportError(cx, "Return type must have defined size");
  1.5403 +    return nullptr;
  1.5404 +  }
  1.5405 +
  1.5406 +  // libffi cannot pass types of zero size by value.
  1.5407 +  JS_ASSERT(typeCode == TYPE_void_t || CType::GetSize(result) != 0);
  1.5408 +
  1.5409 +  return result;
  1.5410 +}
  1.5411 +
  1.5412 +static MOZ_ALWAYS_INLINE bool
  1.5413 +IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
  1.5414 +{
  1.5415 +  *isEllipsis = false;
  1.5416 +  if (!JSVAL_IS_STRING(v))
  1.5417 +    return true;
  1.5418 +  JSString* str = JSVAL_TO_STRING(v);
  1.5419 +  if (str->length() != 3)
  1.5420 +    return true;
  1.5421 +  const jschar* chars = str->getChars(cx);
  1.5422 +  if (!chars)
  1.5423 +    return false;
  1.5424 +  jschar dot = '.';
  1.5425 +  *isEllipsis = (chars[0] == dot &&
  1.5426 +                 chars[1] == dot &&
  1.5427 +                 chars[2] == dot);
  1.5428 +  return true;
  1.5429 +}
  1.5430 +
  1.5431 +static bool
  1.5432 +PrepareCIF(JSContext* cx,
  1.5433 +           FunctionInfo* fninfo)
  1.5434 +{
  1.5435 +  ffi_abi abi;
  1.5436 +  if (!GetABI(cx, OBJECT_TO_JSVAL(fninfo->mABI), &abi)) {
  1.5437 +    JS_ReportError(cx, "Invalid ABI specification");
  1.5438 +    return false;
  1.5439 +  }
  1.5440 +
  1.5441 +  ffi_type* rtype = CType::GetFFIType(cx, fninfo->mReturnType);
  1.5442 +  if (!rtype)
  1.5443 +    return false;
  1.5444 +
  1.5445 +  ffi_status status =
  1.5446 +    ffi_prep_cif(&fninfo->mCIF,
  1.5447 +                 abi,
  1.5448 +                 fninfo->mFFITypes.length(),
  1.5449 +                 rtype,
  1.5450 +                 fninfo->mFFITypes.begin());
  1.5451 +
  1.5452 +  switch (status) {
  1.5453 +  case FFI_OK:
  1.5454 +    return true;
  1.5455 +  case FFI_BAD_ABI:
  1.5456 +    JS_ReportError(cx, "Invalid ABI specification");
  1.5457 +    return false;
  1.5458 +  case FFI_BAD_TYPEDEF:
  1.5459 +    JS_ReportError(cx, "Invalid type specification");
  1.5460 +    return false;
  1.5461 +  default:
  1.5462 +    JS_ReportError(cx, "Unknown libffi error");
  1.5463 +    return false;
  1.5464 +  }
  1.5465 +}
  1.5466 +
  1.5467 +void
  1.5468 +FunctionType::BuildSymbolName(JSString* name,
  1.5469 +                              JSObject* typeObj,
  1.5470 +                              AutoCString& result)
  1.5471 +{
  1.5472 +  FunctionInfo* fninfo = GetFunctionInfo(typeObj);
  1.5473 +
  1.5474 +  switch (GetABICode(fninfo->mABI)) {
  1.5475 +  case ABI_DEFAULT:
  1.5476 +  case ABI_WINAPI:
  1.5477 +    // For cdecl or WINAPI functions, no mangling is necessary.
  1.5478 +    AppendString(result, name);
  1.5479 +    break;
  1.5480 +
  1.5481 +  case ABI_STDCALL: {
  1.5482 +#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
  1.5483 +    // On WIN32, stdcall functions look like:
  1.5484 +    //   _foo@40
  1.5485 +    // where 'foo' is the function name, and '40' is the aligned size of the
  1.5486 +    // arguments.
  1.5487 +    AppendString(result, "_");
  1.5488 +    AppendString(result, name);
  1.5489 +    AppendString(result, "@");
  1.5490 +
  1.5491 +    // Compute the suffix by aligning each argument to sizeof(ffi_arg).
  1.5492 +    size_t size = 0;
  1.5493 +    for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  1.5494 +      JSObject* argType = fninfo->mArgTypes[i];
  1.5495 +      size += Align(CType::GetSize(argType), sizeof(ffi_arg));
  1.5496 +    }
  1.5497 +
  1.5498 +    IntegerToString(size, 10, result);
  1.5499 +#elif defined(_WIN64)
  1.5500 +    // On Win64, stdcall is an alias to the default ABI for compatibility, so no
  1.5501 +    // mangling is done.
  1.5502 +    AppendString(result, name);
  1.5503 +#endif
  1.5504 +    break;
  1.5505 +  }
  1.5506 +
  1.5507 +  case INVALID_ABI:
  1.5508 +    MOZ_ASSUME_UNREACHABLE("invalid abi");
  1.5509 +  }
  1.5510 +}
  1.5511 +
  1.5512 +static FunctionInfo*
  1.5513 +NewFunctionInfo(JSContext* cx,
  1.5514 +                jsval abiType,
  1.5515 +                jsval returnType,
  1.5516 +                jsval* argTypes,
  1.5517 +                unsigned argLength)
  1.5518 +{
  1.5519 +  AutoPtr<FunctionInfo> fninfo(cx->new_<FunctionInfo>());
  1.5520 +  if (!fninfo) {
  1.5521 +    JS_ReportOutOfMemory(cx);
  1.5522 +    return nullptr;
  1.5523 +  }
  1.5524 +
  1.5525 +  ffi_abi abi;
  1.5526 +  if (!GetABI(cx, abiType, &abi)) {
  1.5527 +    JS_ReportError(cx, "Invalid ABI specification");
  1.5528 +    return nullptr;
  1.5529 +  }
  1.5530 +  fninfo->mABI = JSVAL_TO_OBJECT(abiType);
  1.5531 +
  1.5532 +  // prepare the result type
  1.5533 +  fninfo->mReturnType = PrepareReturnType(cx, returnType);
  1.5534 +  if (!fninfo->mReturnType)
  1.5535 +    return nullptr;
  1.5536 +
  1.5537 +  // prepare the argument types
  1.5538 +  if (!fninfo->mArgTypes.reserve(argLength) ||
  1.5539 +      !fninfo->mFFITypes.reserve(argLength)) {
  1.5540 +    JS_ReportOutOfMemory(cx);
  1.5541 +    return nullptr;
  1.5542 +  }
  1.5543 +
  1.5544 +  fninfo->mIsVariadic = false;
  1.5545 +
  1.5546 +  for (uint32_t i = 0; i < argLength; ++i) {
  1.5547 +    bool isEllipsis;
  1.5548 +    if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
  1.5549 +      return nullptr;
  1.5550 +    if (isEllipsis) {
  1.5551 +      fninfo->mIsVariadic = true;
  1.5552 +      if (i < 1) {
  1.5553 +        JS_ReportError(cx, "\"...\" may not be the first and only parameter "
  1.5554 +                       "type of a variadic function declaration");
  1.5555 +        return nullptr;
  1.5556 +      }
  1.5557 +      if (i < argLength - 1) {
  1.5558 +        JS_ReportError(cx, "\"...\" must be the last parameter type of a "
  1.5559 +                       "variadic function declaration");
  1.5560 +        return nullptr;
  1.5561 +      }
  1.5562 +      if (GetABICode(fninfo->mABI) != ABI_DEFAULT) {
  1.5563 +        JS_ReportError(cx, "Variadic functions must use the __cdecl calling "
  1.5564 +                       "convention");
  1.5565 +        return nullptr;
  1.5566 +      }
  1.5567 +      break;
  1.5568 +    }
  1.5569 +
  1.5570 +    JSObject* argType = PrepareType(cx, argTypes[i]);
  1.5571 +    if (!argType)
  1.5572 +      return nullptr;
  1.5573 +
  1.5574 +    ffi_type* ffiType = CType::GetFFIType(cx, argType);
  1.5575 +    if (!ffiType)
  1.5576 +      return nullptr;
  1.5577 +
  1.5578 +    fninfo->mArgTypes.infallibleAppend(argType);
  1.5579 +    fninfo->mFFITypes.infallibleAppend(ffiType);
  1.5580 +  }
  1.5581 +
  1.5582 +  if (fninfo->mIsVariadic)
  1.5583 +    // wait to PrepareCIF until function is called
  1.5584 +    return fninfo.forget();
  1.5585 +
  1.5586 +  if (!PrepareCIF(cx, fninfo.get()))
  1.5587 +    return nullptr;
  1.5588 +
  1.5589 +  return fninfo.forget();
  1.5590 +}
  1.5591 +
  1.5592 +bool
  1.5593 +FunctionType::Create(JSContext* cx, unsigned argc, jsval* vp)
  1.5594 +{
  1.5595 +  // Construct and return a new FunctionType object.
  1.5596 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.5597 +  if (args.length() < 2 || args.length() > 3) {
  1.5598 +    JS_ReportError(cx, "FunctionType takes two or three arguments");
  1.5599 +    return false;
  1.5600 +  }
  1.5601 +
  1.5602 +  AutoValueVector argTypes(cx);
  1.5603 +  RootedObject arrayObj(cx, nullptr);
  1.5604 +
  1.5605 +  if (args.length() == 3) {
  1.5606 +    // Prepare an array of jsvals for the arguments.
  1.5607 +    if (!JSVAL_IS_PRIMITIVE(args[2]))
  1.5608 +      arrayObj = &args[2].toObject();
  1.5609 +    if (!arrayObj || !JS_IsArrayObject(cx, arrayObj)) {
  1.5610 +      JS_ReportError(cx, "third argument must be an array");
  1.5611 +      return false;
  1.5612 +    }
  1.5613 +
  1.5614 +    uint32_t len;
  1.5615 +    ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len));
  1.5616 +
  1.5617 +    if (!argTypes.resize(len)) {
  1.5618 +      JS_ReportOutOfMemory(cx);
  1.5619 +      return false;
  1.5620 +    }
  1.5621 +  }
  1.5622 +
  1.5623 +  // Pull out the argument types from the array, if any.
  1.5624 +  JS_ASSERT_IF(argTypes.length(), arrayObj);
  1.5625 +  for (uint32_t i = 0; i < argTypes.length(); ++i) {
  1.5626 +    if (!JS_GetElement(cx, arrayObj, i, argTypes.handleAt(i)))
  1.5627 +      return false;
  1.5628 +  }
  1.5629 +
  1.5630 +  JSObject* result = CreateInternal(cx, args[0], args[1],
  1.5631 +      argTypes.begin(), argTypes.length());
  1.5632 +  if (!result)
  1.5633 +    return false;
  1.5634 +
  1.5635 +  args.rval().setObject(*result);
  1.5636 +  return true;
  1.5637 +}
  1.5638 +
  1.5639 +JSObject*
  1.5640 +FunctionType::CreateInternal(JSContext* cx,
  1.5641 +                             jsval abi,
  1.5642 +                             jsval rtype,
  1.5643 +                             jsval* argtypes,
  1.5644 +                             unsigned arglen)
  1.5645 +{
  1.5646 +  // Determine and check the types, and prepare the function CIF.
  1.5647 +  AutoPtr<FunctionInfo> fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen));
  1.5648 +  if (!fninfo)
  1.5649 +    return nullptr;
  1.5650 +
  1.5651 +  // Get ctypes.FunctionType.prototype and the common prototype for CData objects
  1.5652 +  // of this type, from ctypes.CType.prototype.
  1.5653 +  RootedObject typeProto(cx, CType::GetProtoFromType(cx, fninfo->mReturnType,
  1.5654 +                                                     SLOT_FUNCTIONPROTO));
  1.5655 +  if (!typeProto)
  1.5656 +    return nullptr;
  1.5657 +  RootedObject dataProto(cx, CType::GetProtoFromType(cx, fninfo->mReturnType,
  1.5658 +                                                     SLOT_FUNCTIONDATAPROTO));
  1.5659 +  if (!dataProto)
  1.5660 +    return nullptr;
  1.5661 +
  1.5662 +  // Create a new CType object with the common properties and slots.
  1.5663 +  JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_function,
  1.5664 +                        nullptr, JSVAL_VOID, JSVAL_VOID, nullptr);
  1.5665 +  if (!typeObj)
  1.5666 +    return nullptr;
  1.5667 +
  1.5668 +  // Stash the FunctionInfo in a reserved slot.
  1.5669 +  JS_SetReservedSlot(typeObj, SLOT_FNINFO, PRIVATE_TO_JSVAL(fninfo.forget()));
  1.5670 +
  1.5671 +  return typeObj;
  1.5672 +}
  1.5673 +
  1.5674 +// Construct a function pointer to a JS function (see CClosure::Create()).
  1.5675 +// Regular function pointers are constructed directly in
  1.5676 +// PointerType::ConstructData().
  1.5677 +bool
  1.5678 +FunctionType::ConstructData(JSContext* cx,
  1.5679 +                            HandleObject typeObj,
  1.5680 +                            HandleObject dataObj,
  1.5681 +                            HandleObject fnObj,
  1.5682 +                            HandleObject thisObj,
  1.5683 +                            jsval errVal)
  1.5684 +{
  1.5685 +  JS_ASSERT(CType::GetTypeCode(typeObj) == TYPE_function);
  1.5686 +
  1.5687 +  PRFuncPtr* data = static_cast<PRFuncPtr*>(CData::GetData(dataObj));
  1.5688 +
  1.5689 +  FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  1.5690 +  if (fninfo->mIsVariadic) {
  1.5691 +    JS_ReportError(cx, "Can't declare a variadic callback function");
  1.5692 +    return false;
  1.5693 +  }
  1.5694 +  if (GetABICode(fninfo->mABI) == ABI_WINAPI) {
  1.5695 +    JS_ReportError(cx, "Can't declare a ctypes.winapi_abi callback function, "
  1.5696 +                   "use ctypes.stdcall_abi instead");
  1.5697 +    return false;
  1.5698 +  }
  1.5699 +
  1.5700 +  RootedObject closureObj(cx, CClosure::Create(cx, typeObj, fnObj, thisObj, errVal, data));
  1.5701 +  if (!closureObj)
  1.5702 +    return false;
  1.5703 +
  1.5704 +  // Set the closure object as the referent of the new CData object.
  1.5705 +  JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(closureObj));
  1.5706 +
  1.5707 +  // Seal the CData object, to prevent modification of the function pointer.
  1.5708 +  // This permanently associates this object with the closure, and avoids
  1.5709 +  // having to do things like reset SLOT_REFERENT when someone tries to
  1.5710 +  // change the pointer value.
  1.5711 +  // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
  1.5712 +  // could be called on a frozen object.
  1.5713 +  return JS_FreezeObject(cx, dataObj);
  1.5714 +}
  1.5715 +
  1.5716 +typedef Array<AutoValue, 16> AutoValueAutoArray;
  1.5717 +
  1.5718 +static bool
  1.5719 +ConvertArgument(JSContext* cx,
  1.5720 +                HandleValue arg,
  1.5721 +                JSObject* type,
  1.5722 +                AutoValue* value,
  1.5723 +                AutoValueAutoArray* strings)
  1.5724 +{
  1.5725 +  if (!value->SizeToType(cx, type)) {
  1.5726 +    JS_ReportAllocationOverflow(cx);
  1.5727 +    return false;
  1.5728 +  }
  1.5729 +
  1.5730 +  bool freePointer = false;
  1.5731 +  if (!ImplicitConvert(cx, arg, type, value->mData, true, &freePointer))
  1.5732 +    return false;
  1.5733 +
  1.5734 +  if (freePointer) {
  1.5735 +    // ImplicitConvert converted a string for us, which we have to free.
  1.5736 +    // Keep track of it.
  1.5737 +    if (!strings->growBy(1)) {
  1.5738 +      JS_ReportOutOfMemory(cx);
  1.5739 +      return false;
  1.5740 +    }
  1.5741 +    strings->back().mData = *static_cast<char**>(value->mData);
  1.5742 +  }
  1.5743 +
  1.5744 +  return true;
  1.5745 +}
  1.5746 +
  1.5747 +bool
  1.5748 +FunctionType::Call(JSContext* cx,
  1.5749 +                   unsigned argc,
  1.5750 +                   jsval* vp)
  1.5751 +{
  1.5752 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.5753 +  // get the callee object...
  1.5754 +  RootedObject obj(cx, &args.callee());
  1.5755 +  if (!CData::IsCData(obj)) {
  1.5756 +    JS_ReportError(cx, "not a CData");
  1.5757 +    return false;
  1.5758 +  }
  1.5759 +
  1.5760 +  RootedObject typeObj(cx, CData::GetCType(obj));
  1.5761 +  if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  1.5762 +    JS_ReportError(cx, "not a FunctionType.ptr");
  1.5763 +    return false;
  1.5764 +  }
  1.5765 +
  1.5766 +  typeObj = PointerType::GetBaseType(typeObj);
  1.5767 +  if (CType::GetTypeCode(typeObj) != TYPE_function) {
  1.5768 +    JS_ReportError(cx, "not a FunctionType.ptr");
  1.5769 +    return false;
  1.5770 +  }
  1.5771 +
  1.5772 +  FunctionInfo* fninfo = GetFunctionInfo(typeObj);
  1.5773 +  uint32_t argcFixed = fninfo->mArgTypes.length();
  1.5774 +
  1.5775 +  if ((!fninfo->mIsVariadic && args.length() != argcFixed) ||
  1.5776 +      (fninfo->mIsVariadic && args.length() < argcFixed)) {
  1.5777 +    JS_ReportError(cx, "Number of arguments does not match declaration");
  1.5778 +    return false;
  1.5779 +  }
  1.5780 +
  1.5781 +  // Check if we have a Library object. If we do, make sure it's open.
  1.5782 +  jsval slot = JS_GetReservedSlot(obj, SLOT_REFERENT);
  1.5783 +  if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
  1.5784 +    PRLibrary* library = Library::GetLibrary(&slot.toObject());
  1.5785 +    if (!library) {
  1.5786 +      JS_ReportError(cx, "library is not open");
  1.5787 +      return false;
  1.5788 +    }
  1.5789 +  }
  1.5790 +
  1.5791 +  // prepare the values for each argument
  1.5792 +  AutoValueAutoArray values;
  1.5793 +  AutoValueAutoArray strings;
  1.5794 +  if (!values.resize(args.length())) {
  1.5795 +    JS_ReportOutOfMemory(cx);
  1.5796 +    return false;
  1.5797 +  }
  1.5798 +
  1.5799 +  for (unsigned i = 0; i < argcFixed; ++i)
  1.5800 +    if (!ConvertArgument(cx, args[i], fninfo->mArgTypes[i], &values[i], &strings))
  1.5801 +      return false;
  1.5802 +
  1.5803 +  if (fninfo->mIsVariadic) {
  1.5804 +    if (!fninfo->mFFITypes.resize(args.length())) {
  1.5805 +      JS_ReportOutOfMemory(cx);
  1.5806 +      return false;
  1.5807 +    }
  1.5808 +
  1.5809 +    RootedObject obj(cx);  // Could reuse obj instead of declaring a second
  1.5810 +    RootedObject type(cx); // RootedObject, but readability would suffer.
  1.5811 +
  1.5812 +    for (uint32_t i = argcFixed; i < args.length(); ++i) {
  1.5813 +      if (JSVAL_IS_PRIMITIVE(args[i]) ||
  1.5814 +          !CData::IsCData(obj = &args[i].toObject())) {
  1.5815 +        // Since we know nothing about the CTypes of the ... arguments,
  1.5816 +        // they absolutely must be CData objects already.
  1.5817 +        JS_ReportError(cx, "argument %d of type %s is not a CData object",
  1.5818 +                       i, JS_GetTypeName(cx, JS_TypeOfValue(cx, args[i])));
  1.5819 +        return false;
  1.5820 +      }
  1.5821 +      if (!(type = CData::GetCType(obj)) ||
  1.5822 +          !(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) ||
  1.5823 +          // Relying on ImplicitConvert only for the limited purpose of
  1.5824 +          // converting one CType to another (e.g., T[] to T*).
  1.5825 +          !ConvertArgument(cx, args[i], type, &values[i], &strings) ||
  1.5826 +          !(fninfo->mFFITypes[i] = CType::GetFFIType(cx, type))) {
  1.5827 +        // These functions report their own errors.
  1.5828 +        return false;
  1.5829 +      }
  1.5830 +    }
  1.5831 +    if (!PrepareCIF(cx, fninfo))
  1.5832 +      return false;
  1.5833 +  }
  1.5834 +
  1.5835 +  // initialize a pointer to an appropriate location, for storing the result
  1.5836 +  AutoValue returnValue;
  1.5837 +  TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
  1.5838 +  if (typeCode != TYPE_void_t &&
  1.5839 +      !returnValue.SizeToType(cx, fninfo->mReturnType)) {
  1.5840 +    JS_ReportAllocationOverflow(cx);
  1.5841 +    return false;
  1.5842 +  }
  1.5843 +
  1.5844 +  // Let the runtime callback know that we are about to call into C.
  1.5845 +  js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALL_BEGIN, js::CTYPES_CALL_END);
  1.5846 +
  1.5847 +  uintptr_t fn = *reinterpret_cast<uintptr_t*>(CData::GetData(obj));
  1.5848 +
  1.5849 +#if defined(XP_WIN)
  1.5850 +  int32_t lastErrorStatus; // The status as defined by |GetLastError|
  1.5851 +  int32_t savedLastError = GetLastError();
  1.5852 +  SetLastError(0);
  1.5853 +#endif //defined(XP_WIN)
  1.5854 +  int errnoStatus;         // The status as defined by |errno|
  1.5855 +  int savedErrno = errno;
  1.5856 +  errno = 0;
  1.5857 +
  1.5858 +  ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData,
  1.5859 +           reinterpret_cast<void**>(values.begin()));
  1.5860 +
  1.5861 +  // Save error value.
  1.5862 +  // We need to save it before leaving the scope of |suspend| as destructing
  1.5863 +  // |suspend| has the side-effect of clearing |GetLastError|
  1.5864 +  // (see bug 684017).
  1.5865 +
  1.5866 +  errnoStatus = errno;
  1.5867 +#if defined(XP_WIN)
  1.5868 +  lastErrorStatus = GetLastError();
  1.5869 +  SetLastError(savedLastError);
  1.5870 +#endif // defined(XP_WIN)
  1.5871 +
  1.5872 +  errno = savedErrno;
  1.5873 +
  1.5874 +  // We're no longer calling into C.
  1.5875 +  autoCallback.DoEndCallback();
  1.5876 +
  1.5877 +  // Store the error value for later consultation with |ctypes.getStatus|
  1.5878 +  JSObject *objCTypes = CType::GetGlobalCTypes(cx, typeObj);
  1.5879 +  if (!objCTypes)
  1.5880 +    return false;
  1.5881 +
  1.5882 +  JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
  1.5883 +#if defined(XP_WIN)
  1.5884 +  JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
  1.5885 +#endif // defined(XP_WIN)
  1.5886 +
  1.5887 +  // Small integer types get returned as a word-sized ffi_arg. Coerce it back
  1.5888 +  // into the correct size for ConvertToJS.
  1.5889 +  switch (typeCode) {
  1.5890 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.5891 +  case TYPE_##name:                                                            \
  1.5892 +    if (sizeof(type) < sizeof(ffi_arg)) {                                      \
  1.5893 +      ffi_arg data = *static_cast<ffi_arg*>(returnValue.mData);                \
  1.5894 +      *static_cast<type*>(returnValue.mData) = static_cast<type>(data);        \
  1.5895 +    }                                                                          \
  1.5896 +    break;
  1.5897 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.5898 +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.5899 +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.5900 +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.5901 +#include "ctypes/typedefs.h"
  1.5902 +  default:
  1.5903 +    break;
  1.5904 +  }
  1.5905 +
  1.5906 +  // prepare a JS object from the result
  1.5907 +  RootedObject returnType(cx, fninfo->mReturnType);
  1.5908 +  return ConvertToJS(cx, returnType, NullPtr(), returnValue.mData, false, true, vp);
  1.5909 +}
  1.5910 +
  1.5911 +FunctionInfo*
  1.5912 +FunctionType::GetFunctionInfo(JSObject* obj)
  1.5913 +{
  1.5914 +  JS_ASSERT(CType::IsCType(obj));
  1.5915 +  JS_ASSERT(CType::GetTypeCode(obj) == TYPE_function);
  1.5916 +
  1.5917 +  jsval slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
  1.5918 +  JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
  1.5919 +
  1.5920 +  return static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
  1.5921 +}
  1.5922 +
  1.5923 +bool
  1.5924 +FunctionType::IsFunctionType(HandleValue v)
  1.5925 +{
  1.5926 +  if (!v.isObject())
  1.5927 +    return false;
  1.5928 +  JSObject* obj = &v.toObject();
  1.5929 +  return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_function;
  1.5930 +}
  1.5931 +
  1.5932 +bool
  1.5933 +FunctionType::ArgTypesGetter(JSContext* cx, JS::CallArgs args)
  1.5934 +{
  1.5935 +  JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  1.5936 +
  1.5937 +  args.rval().set(JS_GetReservedSlot(obj, SLOT_ARGS_T));
  1.5938 +  if (!args.rval().isUndefined())
  1.5939 +    return true;
  1.5940 +
  1.5941 +  FunctionInfo* fninfo = GetFunctionInfo(obj);
  1.5942 +  size_t len = fninfo->mArgTypes.length();
  1.5943 +
  1.5944 +  // Prepare a new array.
  1.5945 +  JS::Rooted<JSObject*> argTypes(cx);
  1.5946 +  {
  1.5947 +      JS::AutoValueVector vec(cx);
  1.5948 +      if (!vec.resize(len))
  1.5949 +        return false;
  1.5950 +
  1.5951 +      for (size_t i = 0; i < len; ++i)
  1.5952 +        vec[i] = JS::ObjectValue(*fninfo->mArgTypes[i]);
  1.5953 +
  1.5954 +      argTypes = JS_NewArrayObject(cx, vec);
  1.5955 +      if (!argTypes)
  1.5956 +        return false;
  1.5957 +  }
  1.5958 +
  1.5959 +  // Seal and cache it.
  1.5960 +  if (!JS_FreezeObject(cx, argTypes))
  1.5961 +    return false;
  1.5962 +  JS_SetReservedSlot(obj, SLOT_ARGS_T, JS::ObjectValue(*argTypes));
  1.5963 +
  1.5964 +  args.rval().setObject(*argTypes);
  1.5965 +  return true;
  1.5966 +}
  1.5967 +
  1.5968 +bool
  1.5969 +FunctionType::ReturnTypeGetter(JSContext* cx, JS::CallArgs args)
  1.5970 +{
  1.5971 +  // Get the returnType object from the FunctionInfo.
  1.5972 +  args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mReturnType);
  1.5973 +  return true;
  1.5974 +}
  1.5975 +
  1.5976 +bool
  1.5977 +FunctionType::ABIGetter(JSContext* cx, JS::CallArgs args)
  1.5978 +{
  1.5979 +  // Get the abi object from the FunctionInfo.
  1.5980 +  args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mABI);
  1.5981 +  return true;
  1.5982 +}
  1.5983 +
  1.5984 +bool
  1.5985 +FunctionType::IsVariadicGetter(JSContext* cx, JS::CallArgs args)
  1.5986 +{
  1.5987 +  args.rval().setBoolean(GetFunctionInfo(&args.thisv().toObject())->mIsVariadic);
  1.5988 +  return true;
  1.5989 +}
  1.5990 +
  1.5991 +/*******************************************************************************
  1.5992 +** CClosure implementation
  1.5993 +*******************************************************************************/
  1.5994 +
  1.5995 +JSObject*
  1.5996 +CClosure::Create(JSContext* cx,
  1.5997 +                 HandleObject typeObj,
  1.5998 +                 HandleObject fnObj,
  1.5999 +                 HandleObject thisObj,
  1.6000 +                 jsval errVal_,
  1.6001 +                 PRFuncPtr* fnptr)
  1.6002 +{
  1.6003 +  RootedValue errVal(cx, errVal_);
  1.6004 +  JS_ASSERT(fnObj);
  1.6005 +
  1.6006 +  RootedObject result(cx, JS_NewObject(cx, &sCClosureClass, NullPtr(), NullPtr()));
  1.6007 +  if (!result)
  1.6008 +    return nullptr;
  1.6009 +
  1.6010 +  // Get the FunctionInfo from the FunctionType.
  1.6011 +  FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  1.6012 +  JS_ASSERT(!fninfo->mIsVariadic);
  1.6013 +  JS_ASSERT(GetABICode(fninfo->mABI) != ABI_WINAPI);
  1.6014 +
  1.6015 +  AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>(JS_GetRuntime(cx)));
  1.6016 +  if (!cinfo) {
  1.6017 +    JS_ReportOutOfMemory(cx);
  1.6018 +    return nullptr;
  1.6019 +  }
  1.6020 +
  1.6021 +  // Get the prototype of the FunctionType object, of class CTypeProto,
  1.6022 +  // which stores our JSContext for use with the closure.
  1.6023 +  RootedObject proto(cx);
  1.6024 +  if (!JS_GetPrototype(cx, typeObj, &proto))
  1.6025 +    return nullptr;
  1.6026 +  JS_ASSERT(proto);
  1.6027 +  JS_ASSERT(CType::IsCTypeProto(proto));
  1.6028 +
  1.6029 +  // Get a JSContext for use with the closure.
  1.6030 +  cinfo->cx = js::DefaultJSContext(JS_GetRuntime(cx));
  1.6031 +
  1.6032 +  // Prepare the error sentinel value. It's important to do this now, because
  1.6033 +  // we might be unable to convert the value to the proper type. If so, we want
  1.6034 +  // the caller to know about it _now_, rather than some uncertain time in the
  1.6035 +  // future when the error sentinel is actually needed.
  1.6036 +  if (!JSVAL_IS_VOID(errVal)) {
  1.6037 +
  1.6038 +    // Make sure the callback returns something.
  1.6039 +    if (CType::GetTypeCode(fninfo->mReturnType) == TYPE_void_t) {
  1.6040 +      JS_ReportError(cx, "A void callback can't pass an error sentinel");
  1.6041 +      return nullptr;
  1.6042 +    }
  1.6043 +
  1.6044 +    // With the exception of void, the FunctionType constructor ensures that
  1.6045 +    // the return type has a defined size.
  1.6046 +    JS_ASSERT(CType::IsSizeDefined(fninfo->mReturnType));
  1.6047 +
  1.6048 +    // Allocate a buffer for the return value.
  1.6049 +    size_t rvSize = CType::GetSize(fninfo->mReturnType);
  1.6050 +    cinfo->errResult = cx->malloc_(rvSize);
  1.6051 +    if (!cinfo->errResult)
  1.6052 +      return nullptr;
  1.6053 +
  1.6054 +    // Do the value conversion. This might fail, in which case we throw.
  1.6055 +    if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, cinfo->errResult,
  1.6056 +                         false, nullptr))
  1.6057 +      return nullptr;
  1.6058 +  } else {
  1.6059 +    cinfo->errResult = nullptr;
  1.6060 +  }
  1.6061 +
  1.6062 +  // Copy the important bits of context into cinfo.
  1.6063 +  cinfo->closureObj = result;
  1.6064 +  cinfo->typeObj = typeObj;
  1.6065 +  cinfo->thisObj = thisObj;
  1.6066 +  cinfo->jsfnObj = fnObj;
  1.6067 +
  1.6068 +  // Create an ffi_closure object and initialize it.
  1.6069 +  void* code;
  1.6070 +  cinfo->closure =
  1.6071 +    static_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &code));
  1.6072 +  if (!cinfo->closure || !code) {
  1.6073 +    JS_ReportError(cx, "couldn't create closure - libffi error");
  1.6074 +    return nullptr;
  1.6075 +  }
  1.6076 +
  1.6077 +  ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF,
  1.6078 +    CClosure::ClosureStub, cinfo.get(), code);
  1.6079 +  if (status != FFI_OK) {
  1.6080 +    JS_ReportError(cx, "couldn't create closure - libffi error");
  1.6081 +    return nullptr;
  1.6082 +  }
  1.6083 +
  1.6084 +  // Stash the ClosureInfo struct on our new object.
  1.6085 +  JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PRIVATE_TO_JSVAL(cinfo.forget()));
  1.6086 +
  1.6087 +  // Casting between void* and a function pointer is forbidden in C and C++.
  1.6088 +  // Do it via an integral type.
  1.6089 +  *fnptr = reinterpret_cast<PRFuncPtr>(reinterpret_cast<uintptr_t>(code));
  1.6090 +  return result;
  1.6091 +}
  1.6092 +
  1.6093 +void
  1.6094 +CClosure::Trace(JSTracer* trc, JSObject* obj)
  1.6095 +{
  1.6096 +  // Make sure our ClosureInfo slot is legit. If it's not, bail.
  1.6097 +  jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
  1.6098 +  if (JSVAL_IS_VOID(slot))
  1.6099 +    return;
  1.6100 +
  1.6101 +  ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
  1.6102 +
  1.6103 +  // Identify our objects to the tracer. (There's no need to identify
  1.6104 +  // 'closureObj', since that's us.)
  1.6105 +  JS_CallHeapObjectTracer(trc, &cinfo->typeObj, "typeObj");
  1.6106 +  JS_CallHeapObjectTracer(trc, &cinfo->jsfnObj, "jsfnObj");
  1.6107 +  if (cinfo->thisObj)
  1.6108 +    JS_CallHeapObjectTracer(trc, &cinfo->thisObj, "thisObj");
  1.6109 +}
  1.6110 +
  1.6111 +void
  1.6112 +CClosure::Finalize(JSFreeOp *fop, JSObject* obj)
  1.6113 +{
  1.6114 +  // Make sure our ClosureInfo slot is legit. If it's not, bail.
  1.6115 +  jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
  1.6116 +  if (JSVAL_IS_VOID(slot))
  1.6117 +    return;
  1.6118 +
  1.6119 +  ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
  1.6120 +  FreeOp::get(fop)->delete_(cinfo);
  1.6121 +}
  1.6122 +
  1.6123 +void
  1.6124 +CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
  1.6125 +{
  1.6126 +  JS_ASSERT(cif);
  1.6127 +  JS_ASSERT(result);
  1.6128 +  JS_ASSERT(args);
  1.6129 +  JS_ASSERT(userData);
  1.6130 +
  1.6131 +  // Retrieve the essentials from our closure object.
  1.6132 +  ClosureInfo* cinfo = static_cast<ClosureInfo*>(userData);
  1.6133 +  JSContext* cx = cinfo->cx;
  1.6134 +
  1.6135 +  // Let the runtime callback know that we are about to call into JS again. The end callback will
  1.6136 +  // fire automatically when we exit this function.
  1.6137 +  js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
  1.6138 +                                              js::CTYPES_CALLBACK_END);
  1.6139 +
  1.6140 +  RootedObject typeObj(cx, cinfo->typeObj);
  1.6141 +  RootedObject thisObj(cx, cinfo->thisObj);
  1.6142 +  RootedValue jsfnVal(cx, ObjectValue(*cinfo->jsfnObj));
  1.6143 +
  1.6144 +  JS_AbortIfWrongThread(JS_GetRuntime(cx));
  1.6145 +
  1.6146 +  JSAutoRequest ar(cx);
  1.6147 +  JSAutoCompartment ac(cx, cinfo->jsfnObj);
  1.6148 +
  1.6149 +  // Assert that our CIFs agree.
  1.6150 +  FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  1.6151 +  JS_ASSERT(cif == &fninfo->mCIF);
  1.6152 +
  1.6153 +  TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
  1.6154 +
  1.6155 +  // Initialize the result to zero, in case something fails. Small integer types
  1.6156 +  // are promoted to a word-sized ffi_arg, so we must be careful to zero the
  1.6157 +  // whole word.
  1.6158 +  size_t rvSize = 0;
  1.6159 +  if (cif->rtype != &ffi_type_void) {
  1.6160 +    rvSize = cif->rtype->size;
  1.6161 +    switch (typeCode) {
  1.6162 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.6163 +    case TYPE_##name:
  1.6164 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6165 +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6166 +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6167 +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6168 +#include "ctypes/typedefs.h"
  1.6169 +      rvSize = Align(rvSize, sizeof(ffi_arg));
  1.6170 +      break;
  1.6171 +    default:
  1.6172 +      break;
  1.6173 +    }
  1.6174 +    memset(result, 0, rvSize);
  1.6175 +  }
  1.6176 +
  1.6177 +  // Set up an array for converted arguments.
  1.6178 +  JS::AutoValueVector argv(cx);
  1.6179 +  if (!argv.resize(cif->nargs)) {
  1.6180 +    JS_ReportOutOfMemory(cx);
  1.6181 +    return;
  1.6182 +  }
  1.6183 +
  1.6184 +  for (uint32_t i = 0; i < cif->nargs; ++i) {
  1.6185 +    // Convert each argument, and have any CData objects created depend on
  1.6186 +    // the existing buffers.
  1.6187 +    RootedObject argType(cx, fninfo->mArgTypes[i]);
  1.6188 +    if (!ConvertToJS(cx, argType, NullPtr(), args[i], false, false, &argv[i]))
  1.6189 +      return;
  1.6190 +  }
  1.6191 +
  1.6192 +  // Call the JS function. 'thisObj' may be nullptr, in which case the JS
  1.6193 +  // engine will find an appropriate object to use.
  1.6194 +  RootedValue rval(cx);
  1.6195 +  bool success = JS_CallFunctionValue(cx, thisObj, jsfnVal, argv, &rval);
  1.6196 +
  1.6197 +  // Convert the result. Note that we pass 'isArgument = false', such that
  1.6198 +  // ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char
  1.6199 +  // type, which would require an allocation that we can't track. The JS
  1.6200 +  // function must perform this conversion itself and return a PointerType
  1.6201 +  // CData; thusly, the burden of freeing the data is left to the user.
  1.6202 +  if (success && cif->rtype != &ffi_type_void)
  1.6203 +    success = ImplicitConvert(cx, rval, fninfo->mReturnType, result, false,
  1.6204 +                              nullptr);
  1.6205 +
  1.6206 +  if (!success) {
  1.6207 +    // Something failed. The callee may have thrown, or it may not have
  1.6208 +    // returned a value that ImplicitConvert() was happy with. Depending on how
  1.6209 +    // prudent the consumer has been, we may or may not have a recovery plan.
  1.6210 +
  1.6211 +    // In any case, a JS exception cannot be passed to C code, so report the
  1.6212 +    // exception if any and clear it from the cx.
  1.6213 +    if (JS_IsExceptionPending(cx))
  1.6214 +      JS_ReportPendingException(cx);
  1.6215 +
  1.6216 +    if (cinfo->errResult) {
  1.6217 +      // Good case: we have a sentinel that we can return. Copy it in place of
  1.6218 +      // the actual return value, and then proceed.
  1.6219 +
  1.6220 +      // The buffer we're returning might be larger than the size of the return
  1.6221 +      // type, due to libffi alignment issues (see above). But it should never
  1.6222 +      // be smaller.
  1.6223 +      size_t copySize = CType::GetSize(fninfo->mReturnType);
  1.6224 +      JS_ASSERT(copySize <= rvSize);
  1.6225 +      memcpy(result, cinfo->errResult, copySize);
  1.6226 +    } else {
  1.6227 +      // Bad case: not much we can do here. The rv is already zeroed out, so we
  1.6228 +      // just report (another) error and hope for the best. JS_ReportError will
  1.6229 +      // actually throw an exception here, so then we have to report it. Again.
  1.6230 +      // Ugh.
  1.6231 +      JS_ReportError(cx, "JavaScript callback failed, and an error sentinel "
  1.6232 +                         "was not specified.");
  1.6233 +      if (JS_IsExceptionPending(cx))
  1.6234 +        JS_ReportPendingException(cx);
  1.6235 +
  1.6236 +      return;
  1.6237 +    }
  1.6238 +  }
  1.6239 +
  1.6240 +  // Small integer types must be returned as a word-sized ffi_arg. Coerce it
  1.6241 +  // back into the size libffi expects.
  1.6242 +  switch (typeCode) {
  1.6243 +#define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  1.6244 +  case TYPE_##name:                                                            \
  1.6245 +    if (sizeof(type) < sizeof(ffi_arg)) {                                      \
  1.6246 +      ffi_arg data = *static_cast<type*>(result);                              \
  1.6247 +      *static_cast<ffi_arg*>(result) = data;                                   \
  1.6248 +    }                                                                          \
  1.6249 +    break;
  1.6250 +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6251 +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6252 +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6253 +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1.6254 +#include "ctypes/typedefs.h"
  1.6255 +  default:
  1.6256 +    break;
  1.6257 +  }
  1.6258 +}
  1.6259 +
  1.6260 +/*******************************************************************************
  1.6261 +** CData implementation
  1.6262 +*******************************************************************************/
  1.6263 +
  1.6264 +// Create a new CData object of type 'typeObj' containing binary data supplied
  1.6265 +// in 'source', optionally with a referent object 'refObj'.
  1.6266 +//
  1.6267 +// * 'typeObj' must be a CType of defined (but possibly zero) size.
  1.6268 +//
  1.6269 +// * If an object 'refObj' is supplied, the new CData object stores the
  1.6270 +//   referent object in a reserved slot for GC safety, such that 'refObj' will
  1.6271 +//   be held alive by the resulting CData object. 'refObj' may or may not be
  1.6272 +//   a CData object; merely an object we want to keep alive.
  1.6273 +//   * If 'refObj' is a CData object, 'ownResult' must be false.
  1.6274 +//   * Otherwise, 'refObj' is a Library or CClosure object, and 'ownResult'
  1.6275 +//     may be true or false.
  1.6276 +// * Otherwise 'refObj' is nullptr. In this case, 'ownResult' may be true or
  1.6277 +//   false.
  1.6278 +//
  1.6279 +// * If 'ownResult' is true, the CData object will allocate an appropriately
  1.6280 +//   sized buffer, and free it upon finalization. If 'source' data is
  1.6281 +//   supplied, the data will be copied from 'source' into the buffer;
  1.6282 +//   otherwise, the entirety of the new buffer will be initialized to zero.
  1.6283 +// * If 'ownResult' is false, the new CData's buffer refers to a slice of
  1.6284 +//   another buffer kept alive by 'refObj'. 'source' data must be provided,
  1.6285 +//   and the new CData's buffer will refer to 'source'.
  1.6286 +JSObject*
  1.6287 +CData::Create(JSContext* cx,
  1.6288 +              HandleObject typeObj,
  1.6289 +              HandleObject refObj,
  1.6290 +              void* source,
  1.6291 +              bool ownResult)
  1.6292 +{
  1.6293 +  JS_ASSERT(typeObj);
  1.6294 +  JS_ASSERT(CType::IsCType(typeObj));
  1.6295 +  JS_ASSERT(CType::IsSizeDefined(typeObj));
  1.6296 +  JS_ASSERT(ownResult || source);
  1.6297 +  JS_ASSERT_IF(refObj && CData::IsCData(refObj), !ownResult);
  1.6298 +
  1.6299 +  // Get the 'prototype' property from the type.
  1.6300 +  jsval slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
  1.6301 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot));
  1.6302 +
  1.6303 +  RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
  1.6304 +  RootedObject parent(cx, JS_GetParent(typeObj));
  1.6305 +  JS_ASSERT(parent);
  1.6306 +
  1.6307 +  RootedObject dataObj(cx, JS_NewObject(cx, &sCDataClass, proto, parent));
  1.6308 +  if (!dataObj)
  1.6309 +    return nullptr;
  1.6310 +
  1.6311 +  // set the CData's associated type
  1.6312 +  JS_SetReservedSlot(dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj));
  1.6313 +
  1.6314 +  // Stash the referent object, if any, for GC safety.
  1.6315 +  if (refObj)
  1.6316 +    JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(refObj));
  1.6317 +
  1.6318 +  // Set our ownership flag.
  1.6319 +  JS_SetReservedSlot(dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult));
  1.6320 +
  1.6321 +  // attach the buffer. since it might not be 2-byte aligned, we need to
  1.6322 +  // allocate an aligned space for it and store it there. :(
  1.6323 +  char** buffer = cx->new_<char*>();
  1.6324 +  if (!buffer) {
  1.6325 +    JS_ReportOutOfMemory(cx);
  1.6326 +    return nullptr;
  1.6327 +  }
  1.6328 +
  1.6329 +  char* data;
  1.6330 +  if (!ownResult) {
  1.6331 +    data = static_cast<char*>(source);
  1.6332 +  } else {
  1.6333 +    // Initialize our own buffer.
  1.6334 +    size_t size = CType::GetSize(typeObj);
  1.6335 +    data = (char*)cx->malloc_(size);
  1.6336 +    if (!data) {
  1.6337 +      // Report a catchable allocation error.
  1.6338 +      JS_ReportAllocationOverflow(cx);
  1.6339 +      js_free(buffer);
  1.6340 +      return nullptr;
  1.6341 +    }
  1.6342 +
  1.6343 +    if (!source)
  1.6344 +      memset(data, 0, size);
  1.6345 +    else
  1.6346 +      memcpy(data, source, size);
  1.6347 +  }
  1.6348 +
  1.6349 +  *buffer = data;
  1.6350 +  JS_SetReservedSlot(dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer));
  1.6351 +
  1.6352 +  return dataObj;
  1.6353 +}
  1.6354 +
  1.6355 +void
  1.6356 +CData::Finalize(JSFreeOp *fop, JSObject* obj)
  1.6357 +{
  1.6358 +  // Delete our buffer, and the data it contains if we own it.
  1.6359 +  jsval slot = JS_GetReservedSlot(obj, SLOT_OWNS);
  1.6360 +  if (JSVAL_IS_VOID(slot))
  1.6361 +    return;
  1.6362 +
  1.6363 +  bool owns = JSVAL_TO_BOOLEAN(slot);
  1.6364 +
  1.6365 +  slot = JS_GetReservedSlot(obj, SLOT_DATA);
  1.6366 +  if (JSVAL_IS_VOID(slot))
  1.6367 +    return;
  1.6368 +  char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
  1.6369 +
  1.6370 +  if (owns)
  1.6371 +    FreeOp::get(fop)->free_(*buffer);
  1.6372 +  FreeOp::get(fop)->delete_(buffer);
  1.6373 +}
  1.6374 +
  1.6375 +JSObject*
  1.6376 +CData::GetCType(JSObject* dataObj)
  1.6377 +{
  1.6378 +  JS_ASSERT(CData::IsCData(dataObj));
  1.6379 +
  1.6380 +  jsval slot = JS_GetReservedSlot(dataObj, SLOT_CTYPE);
  1.6381 +  JSObject* typeObj = JSVAL_TO_OBJECT(slot);
  1.6382 +  JS_ASSERT(CType::IsCType(typeObj));
  1.6383 +  return typeObj;
  1.6384 +}
  1.6385 +
  1.6386 +void*
  1.6387 +CData::GetData(JSObject* dataObj)
  1.6388 +{
  1.6389 +  JS_ASSERT(CData::IsCData(dataObj));
  1.6390 +
  1.6391 +  jsval slot = JS_GetReservedSlot(dataObj, SLOT_DATA);
  1.6392 +
  1.6393 +  void** buffer = static_cast<void**>(JSVAL_TO_PRIVATE(slot));
  1.6394 +  JS_ASSERT(buffer);
  1.6395 +  JS_ASSERT(*buffer);
  1.6396 +  return *buffer;
  1.6397 +}
  1.6398 +
  1.6399 +bool
  1.6400 +CData::IsCData(JSObject* obj)
  1.6401 +{
  1.6402 +  return JS_GetClass(obj) == &sCDataClass;
  1.6403 +}
  1.6404 +
  1.6405 +bool
  1.6406 +CData::IsCData(HandleValue v)
  1.6407 +{
  1.6408 +  return v.isObject() && CData::IsCData(&v.toObject());
  1.6409 +}
  1.6410 +
  1.6411 +bool
  1.6412 +CData::IsCDataProto(JSObject* obj)
  1.6413 +{
  1.6414 +  return JS_GetClass(obj) == &sCDataProtoClass;
  1.6415 +}
  1.6416 +
  1.6417 +bool
  1.6418 +CData::ValueGetter(JSContext* cx, JS::CallArgs args)
  1.6419 +{
  1.6420 +  RootedObject obj(cx, &args.thisv().toObject());
  1.6421 +
  1.6422 +  // Convert the value to a primitive; do not create a new CData object.
  1.6423 +  RootedObject ctype(cx, GetCType(obj));
  1.6424 +  return ConvertToJS(cx, ctype, NullPtr(), GetData(obj), true, false, args.rval().address());
  1.6425 +}
  1.6426 +
  1.6427 +bool
  1.6428 +CData::ValueSetter(JSContext* cx, JS::CallArgs args)
  1.6429 +{
  1.6430 +  RootedObject obj(cx, &args.thisv().toObject());
  1.6431 +  args.rval().setUndefined();
  1.6432 +  return ImplicitConvert(cx, args.get(0), GetCType(obj), GetData(obj), false, nullptr);
  1.6433 +}
  1.6434 +
  1.6435 +bool
  1.6436 +CData::Address(JSContext* cx, unsigned argc, jsval* vp)
  1.6437 +{
  1.6438 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6439 +  if (args.length() != 0) {
  1.6440 +    JS_ReportError(cx, "address takes zero arguments");
  1.6441 +    return false;
  1.6442 +  }
  1.6443 +
  1.6444 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.6445 +  if (!obj)
  1.6446 +    return false;
  1.6447 +  if (!IsCData(obj)) {
  1.6448 +    JS_ReportError(cx, "not a CData");
  1.6449 +    return false;
  1.6450 +  }
  1.6451 +
  1.6452 +  RootedObject typeObj(cx, CData::GetCType(obj));
  1.6453 +  RootedObject pointerType(cx, PointerType::CreateInternal(cx, typeObj));
  1.6454 +  if (!pointerType)
  1.6455 +    return false;
  1.6456 +
  1.6457 +  // Create a PointerType CData object containing null.
  1.6458 +  JSObject* result = CData::Create(cx, pointerType, NullPtr(), nullptr, true);
  1.6459 +  if (!result)
  1.6460 +    return false;
  1.6461 +
  1.6462 +  args.rval().setObject(*result);
  1.6463 +
  1.6464 +  // Manually set the pointer inside the object, so we skip the conversion step.
  1.6465 +  void** data = static_cast<void**>(GetData(result));
  1.6466 +  *data = GetData(obj);
  1.6467 +  return true;
  1.6468 +}
  1.6469 +
  1.6470 +bool
  1.6471 +CData::Cast(JSContext* cx, unsigned argc, jsval* vp)
  1.6472 +{
  1.6473 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6474 +  if (args.length() != 2) {
  1.6475 +    JS_ReportError(cx, "cast takes two arguments");
  1.6476 +    return false;
  1.6477 +  }
  1.6478 +
  1.6479 +  if (JSVAL_IS_PRIMITIVE(args[0]) ||
  1.6480 +      !CData::IsCData(&args[0].toObject())) {
  1.6481 +    JS_ReportError(cx, "first argument must be a CData");
  1.6482 +    return false;
  1.6483 +  }
  1.6484 +  RootedObject sourceData(cx, &args[0].toObject());
  1.6485 +  JSObject* sourceType = CData::GetCType(sourceData);
  1.6486 +
  1.6487 +  if (JSVAL_IS_PRIMITIVE(args[1]) ||
  1.6488 +      !CType::IsCType(&args[1].toObject())) {
  1.6489 +    JS_ReportError(cx, "second argument must be a CType");
  1.6490 +    return false;
  1.6491 +  }
  1.6492 +
  1.6493 +  RootedObject targetType(cx, &args[1].toObject());
  1.6494 +  size_t targetSize;
  1.6495 +  if (!CType::GetSafeSize(targetType, &targetSize) ||
  1.6496 +      targetSize > CType::GetSize(sourceType)) {
  1.6497 +    JS_ReportError(cx,
  1.6498 +      "target CType has undefined or larger size than source CType");
  1.6499 +    return false;
  1.6500 +  }
  1.6501 +
  1.6502 +  // Construct a new CData object with a type of 'targetType' and a referent
  1.6503 +  // of 'sourceData'.
  1.6504 +  void* data = CData::GetData(sourceData);
  1.6505 +  JSObject* result = CData::Create(cx, targetType, sourceData, data, false);
  1.6506 +  if (!result)
  1.6507 +    return false;
  1.6508 +
  1.6509 +  args.rval().setObject(*result);
  1.6510 +  return true;
  1.6511 +}
  1.6512 +
  1.6513 +bool
  1.6514 +CData::GetRuntime(JSContext* cx, unsigned argc, jsval* vp)
  1.6515 +{
  1.6516 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6517 +  if (args.length() != 1) {
  1.6518 +    JS_ReportError(cx, "getRuntime takes one argument");
  1.6519 +    return false;
  1.6520 +  }
  1.6521 +
  1.6522 +  if (JSVAL_IS_PRIMITIVE(args[0]) ||
  1.6523 +      !CType::IsCType(&args[0].toObject())) {
  1.6524 +    JS_ReportError(cx, "first argument must be a CType");
  1.6525 +    return false;
  1.6526 +  }
  1.6527 +
  1.6528 +  RootedObject targetType(cx, &args[0].toObject());
  1.6529 +  size_t targetSize;
  1.6530 +  if (!CType::GetSafeSize(targetType, &targetSize) ||
  1.6531 +      targetSize != sizeof(void*)) {
  1.6532 +    JS_ReportError(cx, "target CType has non-pointer size");
  1.6533 +    return false;
  1.6534 +  }
  1.6535 +
  1.6536 +  void* data = static_cast<void*>(cx->runtime());
  1.6537 +  JSObject* result = CData::Create(cx, targetType, NullPtr(), &data, true);
  1.6538 +  if (!result)
  1.6539 +    return false;
  1.6540 +
  1.6541 +  args.rval().setObject(*result);
  1.6542 +  return true;
  1.6543 +}
  1.6544 +
  1.6545 +typedef JS::TwoByteCharsZ (*InflateUTF8Method)(JSContext *, const JS::UTF8Chars, size_t *);
  1.6546 +
  1.6547 +static bool
  1.6548 +ReadStringCommon(JSContext* cx, InflateUTF8Method inflateUTF8, unsigned argc, jsval *vp)
  1.6549 +{
  1.6550 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6551 +  if (args.length() != 0) {
  1.6552 +    JS_ReportError(cx, "readString takes zero arguments");
  1.6553 +    return false;
  1.6554 +  }
  1.6555 +
  1.6556 +  JSObject* obj = CDataFinalizer::GetCData(cx, JS_THIS_OBJECT(cx, vp));
  1.6557 +  if (!obj || !CData::IsCData(obj)) {
  1.6558 +    JS_ReportError(cx, "not a CData");
  1.6559 +    return false;
  1.6560 +  }
  1.6561 +
  1.6562 +  // Make sure we are a pointer to, or an array of, an 8-bit or 16-bit
  1.6563 +  // character or integer type.
  1.6564 +  JSObject* baseType;
  1.6565 +  JSObject* typeObj = CData::GetCType(obj);
  1.6566 +  TypeCode typeCode = CType::GetTypeCode(typeObj);
  1.6567 +  void* data;
  1.6568 +  size_t maxLength = -1;
  1.6569 +  switch (typeCode) {
  1.6570 +  case TYPE_pointer:
  1.6571 +    baseType = PointerType::GetBaseType(typeObj);
  1.6572 +    data = *static_cast<void**>(CData::GetData(obj));
  1.6573 +    if (data == nullptr) {
  1.6574 +      JS_ReportError(cx, "cannot read contents of null pointer");
  1.6575 +      return false;
  1.6576 +    }
  1.6577 +    break;
  1.6578 +  case TYPE_array:
  1.6579 +    baseType = ArrayType::GetBaseType(typeObj);
  1.6580 +    data = CData::GetData(obj);
  1.6581 +    maxLength = ArrayType::GetLength(typeObj);
  1.6582 +    break;
  1.6583 +  default:
  1.6584 +    JS_ReportError(cx, "not a PointerType or ArrayType");
  1.6585 +    return false;
  1.6586 +  }
  1.6587 +
  1.6588 +  // Convert the string buffer, taking care to determine the correct string
  1.6589 +  // length in the case of arrays (which may contain embedded nulls).
  1.6590 +  JSString* result;
  1.6591 +  switch (CType::GetTypeCode(baseType)) {
  1.6592 +  case TYPE_int8_t:
  1.6593 +  case TYPE_uint8_t:
  1.6594 +  case TYPE_char:
  1.6595 +  case TYPE_signed_char:
  1.6596 +  case TYPE_unsigned_char: {
  1.6597 +    char* bytes = static_cast<char*>(data);
  1.6598 +    size_t length = strnlen(bytes, maxLength);
  1.6599 +
  1.6600 +    // Determine the length.
  1.6601 +    jschar *dst = inflateUTF8(cx, JS::UTF8Chars(bytes, length), &length).get();
  1.6602 +    if (!dst)
  1.6603 +      return false;
  1.6604 +
  1.6605 +    result = JS_NewUCString(cx, dst, length);
  1.6606 +    break;
  1.6607 +  }
  1.6608 +  case TYPE_int16_t:
  1.6609 +  case TYPE_uint16_t:
  1.6610 +  case TYPE_short:
  1.6611 +  case TYPE_unsigned_short:
  1.6612 +  case TYPE_jschar: {
  1.6613 +    jschar* chars = static_cast<jschar*>(data);
  1.6614 +    size_t length = strnlen(chars, maxLength);
  1.6615 +    result = JS_NewUCStringCopyN(cx, chars, length);
  1.6616 +    break;
  1.6617 +  }
  1.6618 +  default:
  1.6619 +    JS_ReportError(cx,
  1.6620 +      "base type is not an 8-bit or 16-bit integer or character type");
  1.6621 +    return false;
  1.6622 +  }
  1.6623 +
  1.6624 +  if (!result)
  1.6625 +    return false;
  1.6626 +
  1.6627 +  args.rval().setString(result);
  1.6628 +  return true;
  1.6629 +}
  1.6630 +
  1.6631 +bool
  1.6632 +CData::ReadString(JSContext* cx, unsigned argc, jsval* vp)
  1.6633 +{
  1.6634 +  return ReadStringCommon(cx, JS::UTF8CharsToNewTwoByteCharsZ, argc, vp);
  1.6635 +}
  1.6636 +
  1.6637 +bool
  1.6638 +CData::ReadStringReplaceMalformed(JSContext* cx, unsigned argc, jsval* vp)
  1.6639 +{
  1.6640 +  return ReadStringCommon(cx, JS::LossyUTF8CharsToNewTwoByteCharsZ, argc, vp);
  1.6641 +}
  1.6642 +
  1.6643 +JSString *
  1.6644 +CData::GetSourceString(JSContext *cx, HandleObject typeObj, void *data)
  1.6645 +{
  1.6646 +  // Walk the types, building up the toSource() string.
  1.6647 +  // First, we build up the type expression:
  1.6648 +  // 't.ptr' for pointers;
  1.6649 +  // 't.array([n])' for arrays;
  1.6650 +  // 'n' for structs, where n = t.name, the struct's name. (We assume this is
  1.6651 +  // bound to a variable in the current scope.)
  1.6652 +  AutoString source;
  1.6653 +  BuildTypeSource(cx, typeObj, true, source);
  1.6654 +  AppendString(source, "(");
  1.6655 +  if (!BuildDataSource(cx, typeObj, data, false, source))
  1.6656 +    return nullptr;
  1.6657 +
  1.6658 +  AppendString(source, ")");
  1.6659 +
  1.6660 +  return NewUCString(cx, source);
  1.6661 +}
  1.6662 +
  1.6663 +bool
  1.6664 +CData::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  1.6665 +{
  1.6666 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6667 +  if (args.length() != 0) {
  1.6668 +    JS_ReportError(cx, "toSource takes zero arguments");
  1.6669 +    return false;
  1.6670 +  }
  1.6671 +
  1.6672 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.6673 +  if (!obj)
  1.6674 +    return false;
  1.6675 +  if (!CData::IsCData(obj) && !CData::IsCDataProto(obj)) {
  1.6676 +    JS_ReportError(cx, "not a CData");
  1.6677 +    return false;
  1.6678 +  }
  1.6679 +
  1.6680 +  JSString* result;
  1.6681 +  if (CData::IsCData(obj)) {
  1.6682 +    RootedObject typeObj(cx, CData::GetCType(obj));
  1.6683 +    void* data = CData::GetData(obj);
  1.6684 +
  1.6685 +    result = CData::GetSourceString(cx, typeObj, data);
  1.6686 +  } else {
  1.6687 +    result = JS_NewStringCopyZ(cx, "[CData proto object]");
  1.6688 +  }
  1.6689 +
  1.6690 +  if (!result)
  1.6691 +    return false;
  1.6692 +
  1.6693 +  args.rval().setString(result);
  1.6694 +  return true;
  1.6695 +}
  1.6696 +
  1.6697 +bool
  1.6698 +CData::ErrnoGetter(JSContext* cx, JS::CallArgs args)
  1.6699 +{
  1.6700 +  args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_ERRNO));
  1.6701 +  return true;
  1.6702 +}
  1.6703 +
  1.6704 +#if defined(XP_WIN)
  1.6705 +bool
  1.6706 +CData::LastErrorGetter(JSContext* cx, JS::CallArgs args)
  1.6707 +{
  1.6708 +  args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_LASTERROR));
  1.6709 +  return true;
  1.6710 +}
  1.6711 +#endif // defined(XP_WIN)
  1.6712 +
  1.6713 +bool
  1.6714 +CDataFinalizer::Methods::ToSource(JSContext *cx, unsigned argc, jsval *vp)
  1.6715 +{
  1.6716 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6717 +  RootedObject objThis(cx, JS_THIS_OBJECT(cx, vp));
  1.6718 +  if (!objThis)
  1.6719 +    return false;
  1.6720 +  if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
  1.6721 +    JS_ReportError(cx, "not a CDataFinalizer");
  1.6722 +    return false;
  1.6723 +  }
  1.6724 +
  1.6725 +  CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.6726 +    JS_GetPrivate(objThis);
  1.6727 +
  1.6728 +  JSString *strMessage;
  1.6729 +  if (!p) {
  1.6730 +    strMessage = JS_NewStringCopyZ(cx, "ctypes.CDataFinalizer()");
  1.6731 +  } else {
  1.6732 +    RootedObject objType(cx, CDataFinalizer::GetCType(cx, objThis));
  1.6733 +    if (!objType) {
  1.6734 +      JS_ReportError(cx, "CDataFinalizer has no type");
  1.6735 +      return false;
  1.6736 +    }
  1.6737 +
  1.6738 +    AutoString source;
  1.6739 +    AppendString(source, "ctypes.CDataFinalizer(");
  1.6740 +    JSString *srcValue = CData::GetSourceString(cx, objType, p->cargs);
  1.6741 +    if (!srcValue) {
  1.6742 +      return false;
  1.6743 +    }
  1.6744 +    AppendString(source, srcValue);
  1.6745 +    AppendString(source, ", ");
  1.6746 +    jsval valCodePtrType = JS_GetReservedSlot(objThis,
  1.6747 +                                              SLOT_DATAFINALIZER_CODETYPE);
  1.6748 +    if (JSVAL_IS_PRIMITIVE(valCodePtrType)) {
  1.6749 +      return false;
  1.6750 +    }
  1.6751 +
  1.6752 +    RootedObject typeObj(cx, JSVAL_TO_OBJECT(valCodePtrType));
  1.6753 +    JSString *srcDispose = CData::GetSourceString(cx, typeObj, &(p->code));
  1.6754 +    if (!srcDispose) {
  1.6755 +      return false;
  1.6756 +    }
  1.6757 +
  1.6758 +    AppendString(source, srcDispose);
  1.6759 +    AppendString(source, ")");
  1.6760 +    strMessage = NewUCString(cx, source);
  1.6761 +  }
  1.6762 +
  1.6763 +  if (!strMessage) {
  1.6764 +    // This is a memory issue, no error message
  1.6765 +    return false;
  1.6766 +  }
  1.6767 +
  1.6768 +  args.rval().setString(strMessage);
  1.6769 +  return true;
  1.6770 +}
  1.6771 +
  1.6772 +bool
  1.6773 +CDataFinalizer::Methods::ToString(JSContext *cx, unsigned argc, jsval *vp)
  1.6774 +{
  1.6775 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6776 +  JSObject* objThis = JS_THIS_OBJECT(cx, vp);
  1.6777 +  if (!objThis)
  1.6778 +    return false;
  1.6779 +  if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
  1.6780 +    JS_ReportError(cx, "not a CDataFinalizer");
  1.6781 +    return false;
  1.6782 +  }
  1.6783 +
  1.6784 +  JSString *strMessage;
  1.6785 +  RootedValue value(cx);
  1.6786 +  if (!JS_GetPrivate(objThis)) {
  1.6787 +    // Pre-check whether CDataFinalizer::GetValue can fail
  1.6788 +    // to avoid reporting an error when not appropriate.
  1.6789 +    strMessage = JS_NewStringCopyZ(cx, "[CDataFinalizer - empty]");
  1.6790 +    if (!strMessage) {
  1.6791 +      return false;
  1.6792 +    }
  1.6793 +  } else if (!CDataFinalizer::GetValue(cx, objThis, value.address())) {
  1.6794 +    MOZ_ASSUME_UNREACHABLE("Could not convert an empty CDataFinalizer");
  1.6795 +  } else {
  1.6796 +    strMessage = ToString(cx, value);
  1.6797 +    if (!strMessage) {
  1.6798 +      return false;
  1.6799 +    }
  1.6800 +  }
  1.6801 +  args.rval().setString(strMessage);
  1.6802 +  return true;
  1.6803 +}
  1.6804 +
  1.6805 +bool
  1.6806 +CDataFinalizer::IsCDataFinalizer(JSObject *obj)
  1.6807 +{
  1.6808 +  return JS_GetClass(obj) == &sCDataFinalizerClass;
  1.6809 +}
  1.6810 +
  1.6811 +
  1.6812 +JSObject *
  1.6813 +CDataFinalizer::GetCType(JSContext *cx, JSObject *obj)
  1.6814 +{
  1.6815 +  MOZ_ASSERT(IsCDataFinalizer(obj));
  1.6816 +
  1.6817 +  jsval valData = JS_GetReservedSlot(obj,
  1.6818 +                                     SLOT_DATAFINALIZER_VALTYPE);
  1.6819 +  if (JSVAL_IS_VOID(valData)) {
  1.6820 +    return nullptr;
  1.6821 +  }
  1.6822 +
  1.6823 +  return JSVAL_TO_OBJECT(valData);
  1.6824 +}
  1.6825 +
  1.6826 +JSObject*
  1.6827 +CDataFinalizer::GetCData(JSContext *cx, JSObject *obj)
  1.6828 +{
  1.6829 +  if (!obj) {
  1.6830 +    JS_ReportError(cx, "No C data");
  1.6831 +    return nullptr;
  1.6832 +  }
  1.6833 +  if (CData::IsCData(obj)) {
  1.6834 +    return obj;
  1.6835 +  }
  1.6836 +  if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  1.6837 +    JS_ReportError(cx, "Not C data");
  1.6838 +    return nullptr;
  1.6839 +  }
  1.6840 +  RootedValue val(cx);
  1.6841 +  if (!CDataFinalizer::GetValue(cx, obj, val.address()) || JSVAL_IS_PRIMITIVE(val)) {
  1.6842 +    JS_ReportError(cx, "Empty CDataFinalizer");
  1.6843 +    return nullptr;
  1.6844 +  }
  1.6845 +  return JSVAL_TO_OBJECT(val);
  1.6846 +}
  1.6847 +
  1.6848 +bool
  1.6849 +CDataFinalizer::GetValue(JSContext *cx, JSObject *obj, jsval *aResult)
  1.6850 +{
  1.6851 +  MOZ_ASSERT(IsCDataFinalizer(obj));
  1.6852 +
  1.6853 +  CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.6854 +    JS_GetPrivate(obj);
  1.6855 +
  1.6856 +  if (!p) {
  1.6857 +    JS_ReportError(cx, "Attempting to get the value of an empty CDataFinalizer");
  1.6858 +    return false;  // We have called |dispose| or |forget| already.
  1.6859 +  }
  1.6860 +
  1.6861 +  RootedObject ctype(cx, GetCType(cx, obj));
  1.6862 +  return ConvertToJS(cx, ctype, /*parent*/NullPtr(), p -> cargs, false, true, aResult);
  1.6863 +}
  1.6864 +
  1.6865 +/*
  1.6866 + * Attach a C function as a finalizer to a JS object.
  1.6867 + *
  1.6868 + * Pseudo-JS signature:
  1.6869 + * function(CData<T>, CData<T -> U>): CDataFinalizer<T>
  1.6870 + *          value,    finalizer
  1.6871 + *
  1.6872 + * This function attaches strong references to the following values:
  1.6873 + * - the CType of |value|
  1.6874 + *
  1.6875 + * Note: This function takes advantage of the fact that non-variadic
  1.6876 + * CData functions are initialized during creation.
  1.6877 + */
  1.6878 +bool
  1.6879 +CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval *vp)
  1.6880 +{
  1.6881 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.6882 +  RootedObject objSelf(cx, &args.callee());
  1.6883 +  RootedObject objProto(cx);
  1.6884 +  if (!GetObjectProperty(cx, objSelf, "prototype", &objProto)) {
  1.6885 +    JS_ReportError(cx, "CDataFinalizer.prototype does not exist");
  1.6886 +    return false;
  1.6887 +  }
  1.6888 +
  1.6889 +  // Get arguments
  1.6890 +  if (args.length() == 0) { // Special case: the empty (already finalized) object
  1.6891 +    JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
  1.6892 +    args.rval().setObject(*objResult);
  1.6893 +    return true;
  1.6894 +  }
  1.6895 +
  1.6896 +  if (args.length() != 2) {
  1.6897 +    JS_ReportError(cx, "CDataFinalizer takes 2 arguments");
  1.6898 +    return false;
  1.6899 +  }
  1.6900 +
  1.6901 +  JS::HandleValue valCodePtr = args[1];
  1.6902 +  if (!valCodePtr.isObject()) {
  1.6903 +    return TypeError(cx, "_a CData object_ of a function pointer type",
  1.6904 +                     valCodePtr);
  1.6905 +  }
  1.6906 +  JSObject *objCodePtr = &valCodePtr.toObject();
  1.6907 +
  1.6908 +  //Note: Using a custom argument formatter here would be awkward (requires
  1.6909 +  //a destructor just to uninstall the formatter).
  1.6910 +
  1.6911 +  // 2. Extract argument type of |objCodePtr|
  1.6912 +  if (!CData::IsCData(objCodePtr)) {
  1.6913 +    return TypeError(cx, "a _CData_ object of a function pointer type",
  1.6914 +                     valCodePtr);
  1.6915 +  }
  1.6916 +  RootedObject objCodePtrType(cx, CData::GetCType(objCodePtr));
  1.6917 +  RootedValue valCodePtrType(cx, ObjectValue(*objCodePtrType));
  1.6918 +  MOZ_ASSERT(objCodePtrType);
  1.6919 +
  1.6920 +  TypeCode typCodePtr = CType::GetTypeCode(objCodePtrType);
  1.6921 +  if (typCodePtr != TYPE_pointer) {
  1.6922 +    return TypeError(cx, "a CData object of a function _pointer_ type",
  1.6923 +                     valCodePtrType);
  1.6924 +  }
  1.6925 +
  1.6926 +  JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType);
  1.6927 +  MOZ_ASSERT(objCodeType);
  1.6928 +
  1.6929 +  TypeCode typCode = CType::GetTypeCode(objCodeType);
  1.6930 +  if (typCode != TYPE_function) {
  1.6931 +    return TypeError(cx, "a CData object of a _function_ pointer type",
  1.6932 +                     valCodePtrType);
  1.6933 +  }
  1.6934 +  uintptr_t code = *reinterpret_cast<uintptr_t*>(CData::GetData(objCodePtr));
  1.6935 +  if (!code) {
  1.6936 +    return TypeError(cx, "a CData object of a _non-NULL_ function pointer type",
  1.6937 +                     valCodePtrType);
  1.6938 +  }
  1.6939 +
  1.6940 +  FunctionInfo* funInfoFinalizer =
  1.6941 +    FunctionType::GetFunctionInfo(objCodeType);
  1.6942 +  MOZ_ASSERT(funInfoFinalizer);
  1.6943 +
  1.6944 +  if ((funInfoFinalizer->mArgTypes.length() != 1)
  1.6945 +      || (funInfoFinalizer->mIsVariadic)) {
  1.6946 +    RootedValue valCodeType(cx, ObjectValue(*objCodeType));
  1.6947 +    return TypeError(cx, "a function accepting exactly one argument",
  1.6948 +                     valCodeType);
  1.6949 +  }
  1.6950 +  RootedObject objArgType(cx, funInfoFinalizer->mArgTypes[0]);
  1.6951 +  RootedObject returnType(cx, funInfoFinalizer->mReturnType);
  1.6952 +
  1.6953 +  // Invariant: At this stage, we know that funInfoFinalizer->mIsVariadic
  1.6954 +  // is |false|. Therefore, funInfoFinalizer->mCIF has already been initialized.
  1.6955 +
  1.6956 +  bool freePointer = false;
  1.6957 +
  1.6958 +  // 3. Perform dynamic cast of |args[0]| into |objType|, store it in |cargs|
  1.6959 +
  1.6960 +  size_t sizeArg;
  1.6961 +  RootedValue valData(cx, args[0]);
  1.6962 +  if (!CType::GetSafeSize(objArgType, &sizeArg)) {
  1.6963 +    return TypeError(cx, "(an object with known size)", valData);
  1.6964 +  }
  1.6965 +
  1.6966 +  ScopedJSFreePtr<void> cargs(malloc(sizeArg));
  1.6967 +
  1.6968 +  if (!ImplicitConvert(cx, valData, objArgType, cargs.get(),
  1.6969 +                       false, &freePointer)) {
  1.6970 +    RootedValue valArgType(cx, ObjectValue(*objArgType));
  1.6971 +    return TypeError(cx, "(an object that can be converted to the following type)",
  1.6972 +                     valArgType);
  1.6973 +  }
  1.6974 +  if (freePointer) {
  1.6975 +    // Note: We could handle that case, if necessary.
  1.6976 +    JS_ReportError(cx, "Internal Error during CDataFinalizer. Object cannot be represented");
  1.6977 +    return false;
  1.6978 +  }
  1.6979 +
  1.6980 +  // 4. Prepare buffer for holding return value
  1.6981 +
  1.6982 +  ScopedJSFreePtr<void> rvalue;
  1.6983 +  if (CType::GetTypeCode(returnType) != TYPE_void_t) {
  1.6984 +    rvalue = malloc(Align(CType::GetSize(returnType),
  1.6985 +                          sizeof(ffi_arg)));
  1.6986 +  } //Otherwise, simply do not allocate
  1.6987 +
  1.6988 +  // 5. Create |objResult|
  1.6989 +
  1.6990 +  JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
  1.6991 +  if (!objResult) {
  1.6992 +    return false;
  1.6993 +  }
  1.6994 +
  1.6995 +  // If our argument is a CData, it holds a type.
  1.6996 +  // This is the type that we should capture, not that
  1.6997 +  // of the function, which may be less precise.
  1.6998 +  JSObject *objBestArgType = objArgType;
  1.6999 +  if (!JSVAL_IS_PRIMITIVE(valData)) {
  1.7000 +    JSObject *objData = &valData.toObject();
  1.7001 +    if (CData::IsCData(objData)) {
  1.7002 +      objBestArgType = CData::GetCType(objData);
  1.7003 +      size_t sizeBestArg;
  1.7004 +      if (!CType::GetSafeSize(objBestArgType, &sizeBestArg)) {
  1.7005 +        MOZ_ASSUME_UNREACHABLE("object with unknown size");
  1.7006 +      }
  1.7007 +      if (sizeBestArg != sizeArg) {
  1.7008 +        return TypeError(cx, "(an object with the same size as that expected by the C finalization function)", valData);
  1.7009 +      }
  1.7010 +    }
  1.7011 +  }
  1.7012 +
  1.7013 +  // Used by GetCType
  1.7014 +  JS_SetReservedSlot(objResult,
  1.7015 +                     SLOT_DATAFINALIZER_VALTYPE,
  1.7016 +                     OBJECT_TO_JSVAL(objBestArgType));
  1.7017 +
  1.7018 +  // Used by ToSource
  1.7019 +  JS_SetReservedSlot(objResult,
  1.7020 +                     SLOT_DATAFINALIZER_CODETYPE,
  1.7021 +                     OBJECT_TO_JSVAL(objCodePtrType));
  1.7022 +
  1.7023 +  ffi_abi abi;
  1.7024 +  if (!GetABI(cx, OBJECT_TO_JSVAL(funInfoFinalizer->mABI), &abi)) {
  1.7025 +    JS_ReportError(cx, "Internal Error: "
  1.7026 +                   "Invalid ABI specification in CDataFinalizer");
  1.7027 +    return false;
  1.7028 +  }
  1.7029 +
  1.7030 +  ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType);
  1.7031 +  if (!rtype) {
  1.7032 +    JS_ReportError(cx, "Internal Error: "
  1.7033 +                   "Could not access ffi type of CDataFinalizer");
  1.7034 +    return false;
  1.7035 +  }
  1.7036 +
  1.7037 +  // 7. Store C information as private
  1.7038 +  ScopedJSFreePtr<CDataFinalizer::Private>
  1.7039 +    p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private)));
  1.7040 +
  1.7041 +  memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif));
  1.7042 +
  1.7043 +  p->cargs = cargs.forget();
  1.7044 +  p->rvalue = rvalue.forget();
  1.7045 +  p->cargs_size = sizeArg;
  1.7046 +  p->code = code;
  1.7047 +
  1.7048 +
  1.7049 +  JS_SetPrivate(objResult, p.forget());
  1.7050 +  args.rval().setObject(*objResult);
  1.7051 +  return true;
  1.7052 +}
  1.7053 +
  1.7054 +
  1.7055 +/*
  1.7056 + * Actually call the finalizer. Does not perform any cleanup on the object.
  1.7057 + *
  1.7058 + * Preconditions: |this| must be a |CDataFinalizer|, |p| must be non-null.
  1.7059 + * The function fails if |this| has gone through |Forget|/|Dispose|
  1.7060 + * or |Finalize|.
  1.7061 + *
  1.7062 + * This function does not alter the value of |errno|/|GetLastError|.
  1.7063 + *
  1.7064 + * If argument |errnoStatus| is non-nullptr, it receives the value of |errno|
  1.7065 + * immediately after the call. Under Windows, if argument |lastErrorStatus|
  1.7066 + * is non-nullptr, it receives the value of |GetLastError| immediately after
  1.7067 + * the call. On other platforms, |lastErrorStatus| is ignored.
  1.7068 + */
  1.7069 +void
  1.7070 +CDataFinalizer::CallFinalizer(CDataFinalizer::Private *p,
  1.7071 +                              int* errnoStatus,
  1.7072 +                              int32_t* lastErrorStatus)
  1.7073 +{
  1.7074 +  int savedErrno = errno;
  1.7075 +  errno = 0;
  1.7076 +#if defined(XP_WIN)
  1.7077 +  int32_t savedLastError = GetLastError();
  1.7078 +  SetLastError(0);
  1.7079 +#endif // defined(XP_WIN)
  1.7080 +
  1.7081 +  ffi_call(&p->CIF, FFI_FN(p->code), p->rvalue, &p->cargs);
  1.7082 +
  1.7083 +  if (errnoStatus) {
  1.7084 +    *errnoStatus = errno;
  1.7085 +  }
  1.7086 +  errno = savedErrno;
  1.7087 +#if defined(XP_WIN)
  1.7088 +  if (lastErrorStatus) {
  1.7089 +    *lastErrorStatus = GetLastError();
  1.7090 +  }
  1.7091 +  SetLastError(savedLastError);
  1.7092 +#endif // defined(XP_WIN)
  1.7093 +}
  1.7094 +
  1.7095 +/*
  1.7096 + * Forget the value.
  1.7097 + *
  1.7098 + * Preconditions: |this| must be a |CDataFinalizer|.
  1.7099 + * The function fails if |this| has gone through |Forget|/|Dispose|
  1.7100 + * or |Finalize|.
  1.7101 + *
  1.7102 + * Does not call the finalizer. Cleans up the Private memory and releases all
  1.7103 + * strong references.
  1.7104 + */
  1.7105 +bool
  1.7106 +CDataFinalizer::Methods::Forget(JSContext* cx, unsigned argc, jsval *vp)
  1.7107 +{
  1.7108 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7109 +  if (args.length() != 0) {
  1.7110 +    JS_ReportError(cx, "CDataFinalizer.prototype.forget takes no arguments");
  1.7111 +    return false;
  1.7112 +  }
  1.7113 +
  1.7114 +  JS::Rooted<JSObject*> obj(cx, args.thisv().toObjectOrNull());
  1.7115 +  if (!obj)
  1.7116 +    return false;
  1.7117 +  if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  1.7118 +    RootedValue val(cx, ObjectValue(*obj));
  1.7119 +    return TypeError(cx, "a CDataFinalizer", val);
  1.7120 +  }
  1.7121 +
  1.7122 +  CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.7123 +    JS_GetPrivate(obj);
  1.7124 +
  1.7125 +  if (!p) {
  1.7126 +    JS_ReportError(cx, "forget called on an empty CDataFinalizer");
  1.7127 +    return false;
  1.7128 +  }
  1.7129 +
  1.7130 +  RootedValue valJSData(cx);
  1.7131 +  RootedObject ctype(cx, GetCType(cx, obj));
  1.7132 +  if (!ConvertToJS(cx, ctype, NullPtr(), p->cargs, false, true, valJSData.address())) {
  1.7133 +    JS_ReportError(cx, "CDataFinalizer value cannot be represented");
  1.7134 +    return false;
  1.7135 +  }
  1.7136 +
  1.7137 +  CDataFinalizer::Cleanup(p, obj);
  1.7138 +
  1.7139 +  args.rval().set(valJSData);
  1.7140 +  return true;
  1.7141 +}
  1.7142 +
  1.7143 +/*
  1.7144 + * Clean up the value.
  1.7145 + *
  1.7146 + * Preconditions: |this| must be a |CDataFinalizer|.
  1.7147 + * The function fails if |this| has gone through |Forget|/|Dispose|
  1.7148 + * or |Finalize|.
  1.7149 + *
  1.7150 + * Calls the finalizer, cleans up the Private memory and releases all
  1.7151 + * strong references.
  1.7152 + */
  1.7153 +bool
  1.7154 +CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, jsval *vp)
  1.7155 +{
  1.7156 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7157 +  if (args.length() != 0) {
  1.7158 +    JS_ReportError(cx, "CDataFinalizer.prototype.dispose takes no arguments");
  1.7159 +    return false;
  1.7160 +  }
  1.7161 +
  1.7162 +  RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  1.7163 +  if (!obj)
  1.7164 +    return false;
  1.7165 +  if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  1.7166 +    RootedValue val(cx, ObjectValue(*obj));
  1.7167 +    return TypeError(cx, "a CDataFinalizer", val);
  1.7168 +  }
  1.7169 +
  1.7170 +  CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.7171 +    JS_GetPrivate(obj);
  1.7172 +
  1.7173 +  if (!p) {
  1.7174 +    JS_ReportError(cx, "dispose called on an empty CDataFinalizer.");
  1.7175 +    return false;
  1.7176 +  }
  1.7177 +
  1.7178 +  jsval valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE);
  1.7179 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valType));
  1.7180 +
  1.7181 +  JSObject *objCTypes = CType::GetGlobalCTypes(cx, &valType.toObject());
  1.7182 +  if (!objCTypes)
  1.7183 +    return false;
  1.7184 +
  1.7185 +  jsval valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE);
  1.7186 +  JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCodePtrType));
  1.7187 +  JSObject *objCodePtrType = &valCodePtrType.toObject();
  1.7188 +
  1.7189 +  JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType);
  1.7190 +  JS_ASSERT(objCodeType);
  1.7191 +  JS_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function);
  1.7192 +
  1.7193 +  RootedObject resultType(cx, FunctionType::GetFunctionInfo(objCodeType)->mReturnType);
  1.7194 +  RootedValue result(cx, JSVAL_VOID);
  1.7195 +
  1.7196 +  int errnoStatus;
  1.7197 +#if defined(XP_WIN)
  1.7198 +  int32_t lastErrorStatus;
  1.7199 +  CDataFinalizer::CallFinalizer(p, &errnoStatus, &lastErrorStatus);
  1.7200 +#else
  1.7201 +  CDataFinalizer::CallFinalizer(p, &errnoStatus, nullptr);
  1.7202 +#endif // defined(XP_WIN)
  1.7203 +
  1.7204 +  JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
  1.7205 +#if defined(XP_WIN)
  1.7206 +  JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
  1.7207 +#endif // defined(XP_WIN)
  1.7208 +
  1.7209 +  if (ConvertToJS(cx, resultType, NullPtr(), p->rvalue, false, true, result.address())) {
  1.7210 +    CDataFinalizer::Cleanup(p, obj);
  1.7211 +    args.rval().set(result);
  1.7212 +    return true;
  1.7213 +  }
  1.7214 +  CDataFinalizer::Cleanup(p, obj);
  1.7215 +  return false;
  1.7216 +}
  1.7217 +
  1.7218 +/*
  1.7219 + * Perform finalization.
  1.7220 + *
  1.7221 + * Preconditions: |this| must be the result of |CDataFinalizer|.
  1.7222 + * It may have gone through |Forget|/|Dispose|.
  1.7223 + *
  1.7224 + * If |this| has not gone through |Forget|/|Dispose|, calls the
  1.7225 + * finalizer, cleans up the Private memory and releases all
  1.7226 + * strong references.
  1.7227 + */
  1.7228 +void
  1.7229 +CDataFinalizer::Finalize(JSFreeOp* fop, JSObject* obj)
  1.7230 +{
  1.7231 +  CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  1.7232 +    JS_GetPrivate(obj);
  1.7233 +
  1.7234 +  if (!p) {
  1.7235 +    return;
  1.7236 +  }
  1.7237 +
  1.7238 +  CDataFinalizer::CallFinalizer(p, nullptr, nullptr);
  1.7239 +  CDataFinalizer::Cleanup(p, nullptr);
  1.7240 +}
  1.7241 +
  1.7242 +/*
  1.7243 + * Perform cleanup of a CDataFinalizer
  1.7244 + *
  1.7245 + * Release strong references, cleanup |Private|.
  1.7246 + *
  1.7247 + * Argument |p| contains the private information of the CDataFinalizer. If
  1.7248 + * nullptr, this function does nothing.
  1.7249 + * Argument |obj| should contain |nullptr| during finalization (or in any
  1.7250 + * context in which the object itself should not be cleaned up), or a
  1.7251 + * CDataFinalizer object otherwise.
  1.7252 + */
  1.7253 +void
  1.7254 +CDataFinalizer::Cleanup(CDataFinalizer::Private *p, JSObject *obj)
  1.7255 +{
  1.7256 +  if (!p) {
  1.7257 +    return;  // We have already cleaned up
  1.7258 +  }
  1.7259 +
  1.7260 +  free(p->cargs);
  1.7261 +  free(p->rvalue);
  1.7262 +  free(p);
  1.7263 +
  1.7264 +  if (!obj) {
  1.7265 +    return;  // No slots to clean up
  1.7266 +  }
  1.7267 +
  1.7268 +  JS_ASSERT(CDataFinalizer::IsCDataFinalizer(obj));
  1.7269 +
  1.7270 +  JS_SetPrivate(obj, nullptr);
  1.7271 +  for (int i = 0; i < CDATAFINALIZER_SLOTS; ++i) {
  1.7272 +    JS_SetReservedSlot(obj, i, JSVAL_NULL);
  1.7273 +  }
  1.7274 +}
  1.7275 +
  1.7276 +
  1.7277 +/*******************************************************************************
  1.7278 +** Int64 and UInt64 implementation
  1.7279 +*******************************************************************************/
  1.7280 +
  1.7281 +JSObject*
  1.7282 +Int64Base::Construct(JSContext* cx,
  1.7283 +                     HandleObject proto,
  1.7284 +                     uint64_t data,
  1.7285 +                     bool isUnsigned)
  1.7286 +{
  1.7287 +  const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
  1.7288 +  RootedObject parent(cx, JS_GetParent(proto));
  1.7289 +  RootedObject result(cx, JS_NewObject(cx, clasp, proto, parent));
  1.7290 +  if (!result)
  1.7291 +    return nullptr;
  1.7292 +
  1.7293 +  // attach the Int64's data
  1.7294 +  uint64_t* buffer = cx->new_<uint64_t>(data);
  1.7295 +  if (!buffer) {
  1.7296 +    JS_ReportOutOfMemory(cx);
  1.7297 +    return nullptr;
  1.7298 +  }
  1.7299 +
  1.7300 +  JS_SetReservedSlot(result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer));
  1.7301 +
  1.7302 +  if (!JS_FreezeObject(cx, result))
  1.7303 +    return nullptr;
  1.7304 +
  1.7305 +  return result;
  1.7306 +}
  1.7307 +
  1.7308 +void
  1.7309 +Int64Base::Finalize(JSFreeOp *fop, JSObject* obj)
  1.7310 +{
  1.7311 +  jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
  1.7312 +  if (JSVAL_IS_VOID(slot))
  1.7313 +    return;
  1.7314 +
  1.7315 +  FreeOp::get(fop)->delete_(static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot)));
  1.7316 +}
  1.7317 +
  1.7318 +uint64_t
  1.7319 +Int64Base::GetInt(JSObject* obj) {
  1.7320 +  JS_ASSERT(Int64::IsInt64(obj) || UInt64::IsUInt64(obj));
  1.7321 +
  1.7322 +  jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
  1.7323 +  return *static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot));
  1.7324 +}
  1.7325 +
  1.7326 +bool
  1.7327 +Int64Base::ToString(JSContext* cx,
  1.7328 +                    JSObject* obj,
  1.7329 +                    const CallArgs& args,
  1.7330 +                    bool isUnsigned)
  1.7331 +{
  1.7332 +  if (args.length() > 1) {
  1.7333 +    JS_ReportError(cx, "toString takes zero or one argument");
  1.7334 +    return false;
  1.7335 +  }
  1.7336 +
  1.7337 +  int radix = 10;
  1.7338 +  if (args.length() == 1) {
  1.7339 +    jsval arg = args[0];
  1.7340 +    if (arg.isInt32())
  1.7341 +      radix = arg.toInt32();
  1.7342 +    if (!arg.isInt32() || radix < 2 || radix > 36) {
  1.7343 +      JS_ReportError(cx, "radix argument must be an integer between 2 and 36");
  1.7344 +      return false;
  1.7345 +    }
  1.7346 +  }
  1.7347 +
  1.7348 +  AutoString intString;
  1.7349 +  if (isUnsigned) {
  1.7350 +    IntegerToString(GetInt(obj), radix, intString);
  1.7351 +  } else {
  1.7352 +    IntegerToString(static_cast<int64_t>(GetInt(obj)), radix, intString);
  1.7353 +  }
  1.7354 +
  1.7355 +  JSString *result = NewUCString(cx, intString);
  1.7356 +  if (!result)
  1.7357 +    return false;
  1.7358 +
  1.7359 +  args.rval().setString(result);
  1.7360 +  return true;
  1.7361 +}
  1.7362 +
  1.7363 +bool
  1.7364 +Int64Base::ToSource(JSContext* cx,
  1.7365 +                    JSObject* obj,
  1.7366 +                    const CallArgs& args,
  1.7367 +                    bool isUnsigned)
  1.7368 +{
  1.7369 +  if (args.length() != 0) {
  1.7370 +    JS_ReportError(cx, "toSource takes zero arguments");
  1.7371 +    return false;
  1.7372 +  }
  1.7373 +
  1.7374 +  // Return a decimal string suitable for constructing the number.
  1.7375 +  AutoString source;
  1.7376 +  if (isUnsigned) {
  1.7377 +    AppendString(source, "ctypes.UInt64(\"");
  1.7378 +    IntegerToString(GetInt(obj), 10, source);
  1.7379 +  } else {
  1.7380 +    AppendString(source, "ctypes.Int64(\"");
  1.7381 +    IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
  1.7382 +  }
  1.7383 +  AppendString(source, "\")");
  1.7384 +
  1.7385 +  JSString *result = NewUCString(cx, source);
  1.7386 +  if (!result)
  1.7387 +    return false;
  1.7388 +
  1.7389 +  args.rval().setString(result);
  1.7390 +  return true;
  1.7391 +}
  1.7392 +
  1.7393 +bool
  1.7394 +Int64::Construct(JSContext* cx,
  1.7395 +                 unsigned argc,
  1.7396 +                 jsval* vp)
  1.7397 +{
  1.7398 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7399 +
  1.7400 +  // Construct and return a new Int64 object.
  1.7401 +  if (args.length() != 1) {
  1.7402 +    JS_ReportError(cx, "Int64 takes one argument");
  1.7403 +    return false;
  1.7404 +  }
  1.7405 +
  1.7406 +  int64_t i = 0;
  1.7407 +  if (!jsvalToBigInteger(cx, args[0], true, &i))
  1.7408 +    return TypeError(cx, "int64", args[0]);
  1.7409 +
  1.7410 +  // Get ctypes.Int64.prototype from the 'prototype' property of the ctor.
  1.7411 +  RootedValue slot(cx);
  1.7412 +  RootedObject callee(cx, &args.callee());
  1.7413 +  ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
  1.7414 +  RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
  1.7415 +  JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
  1.7416 +
  1.7417 +  JSObject* result = Int64Base::Construct(cx, proto, i, false);
  1.7418 +  if (!result)
  1.7419 +    return false;
  1.7420 +
  1.7421 +  args.rval().setObject(*result);
  1.7422 +  return true;
  1.7423 +}
  1.7424 +
  1.7425 +bool
  1.7426 +Int64::IsInt64(JSObject* obj)
  1.7427 +{
  1.7428 +  return JS_GetClass(obj) == &sInt64Class;
  1.7429 +}
  1.7430 +
  1.7431 +bool
  1.7432 +Int64::ToString(JSContext* cx, unsigned argc, jsval* vp)
  1.7433 +{
  1.7434 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7435 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.7436 +  if (!obj)
  1.7437 +    return false;
  1.7438 +  if (!Int64::IsInt64(obj)) {
  1.7439 +    JS_ReportError(cx, "not an Int64");
  1.7440 +    return false;
  1.7441 +  }
  1.7442 +
  1.7443 +  return Int64Base::ToString(cx, obj, args, false);
  1.7444 +}
  1.7445 +
  1.7446 +bool
  1.7447 +Int64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  1.7448 +{
  1.7449 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7450 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.7451 +  if (!obj)
  1.7452 +    return false;
  1.7453 +  if (!Int64::IsInt64(obj)) {
  1.7454 +    JS_ReportError(cx, "not an Int64");
  1.7455 +    return false;
  1.7456 +  }
  1.7457 +
  1.7458 +  return Int64Base::ToSource(cx, obj, args, false);
  1.7459 +}
  1.7460 +
  1.7461 +bool
  1.7462 +Int64::Compare(JSContext* cx, unsigned argc, jsval* vp)
  1.7463 +{
  1.7464 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7465 +  if (args.length() != 2 ||
  1.7466 +      JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7467 +      JSVAL_IS_PRIMITIVE(args[1]) ||
  1.7468 +      !Int64::IsInt64(&args[0].toObject()) ||
  1.7469 +      !Int64::IsInt64(&args[1].toObject())) {
  1.7470 +    JS_ReportError(cx, "compare takes two Int64 arguments");
  1.7471 +    return false;
  1.7472 +  }
  1.7473 +
  1.7474 +  JSObject* obj1 = &args[0].toObject();
  1.7475 +  JSObject* obj2 = &args[1].toObject();
  1.7476 +
  1.7477 +  int64_t i1 = Int64Base::GetInt(obj1);
  1.7478 +  int64_t i2 = Int64Base::GetInt(obj2);
  1.7479 +
  1.7480 +  if (i1 == i2)
  1.7481 +    args.rval().setInt32(0);
  1.7482 +  else if (i1 < i2)
  1.7483 +    args.rval().setInt32(-1);
  1.7484 +  else
  1.7485 +    args.rval().setInt32(1);
  1.7486 +
  1.7487 +  return true;
  1.7488 +}
  1.7489 +
  1.7490 +#define LO_MASK ((uint64_t(1) << 32) - 1)
  1.7491 +#define INT64_LO(i) ((i) & LO_MASK)
  1.7492 +#define INT64_HI(i) ((i) >> 32)
  1.7493 +
  1.7494 +bool
  1.7495 +Int64::Lo(JSContext* cx, unsigned argc, jsval* vp)
  1.7496 +{
  1.7497 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7498 +  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7499 +      !Int64::IsInt64(&args[0].toObject())) {
  1.7500 +    JS_ReportError(cx, "lo takes one Int64 argument");
  1.7501 +    return false;
  1.7502 +  }
  1.7503 +
  1.7504 +  JSObject* obj = &args[0].toObject();
  1.7505 +  int64_t u = Int64Base::GetInt(obj);
  1.7506 +  double d = uint32_t(INT64_LO(u));
  1.7507 +
  1.7508 +  args.rval().setNumber(d);
  1.7509 +  return true;
  1.7510 +}
  1.7511 +
  1.7512 +bool
  1.7513 +Int64::Hi(JSContext* cx, unsigned argc, jsval* vp)
  1.7514 +{
  1.7515 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7516 +  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7517 +      !Int64::IsInt64(&args[0].toObject())) {
  1.7518 +    JS_ReportError(cx, "hi takes one Int64 argument");
  1.7519 +    return false;
  1.7520 +  }
  1.7521 +
  1.7522 +  JSObject* obj = &args[0].toObject();
  1.7523 +  int64_t u = Int64Base::GetInt(obj);
  1.7524 +  double d = int32_t(INT64_HI(u));
  1.7525 +
  1.7526 +  args.rval().setDouble(d);
  1.7527 +  return true;
  1.7528 +}
  1.7529 +
  1.7530 +bool
  1.7531 +Int64::Join(JSContext* cx, unsigned argc, jsval* vp)
  1.7532 +{
  1.7533 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7534 +  if (args.length() != 2) {
  1.7535 +    JS_ReportError(cx, "join takes two arguments");
  1.7536 +    return false;
  1.7537 +  }
  1.7538 +
  1.7539 +  int32_t hi;
  1.7540 +  uint32_t lo;
  1.7541 +  if (!jsvalToInteger(cx, args[0], &hi))
  1.7542 +    return TypeError(cx, "int32", args[0]);
  1.7543 +  if (!jsvalToInteger(cx, args[1], &lo))
  1.7544 +    return TypeError(cx, "uint32", args[1]);
  1.7545 +
  1.7546 +  int64_t i = (int64_t(hi) << 32) + int64_t(lo);
  1.7547 +
  1.7548 +  // Get Int64.prototype from the function's reserved slot.
  1.7549 +  JSObject* callee = &args.callee();
  1.7550 +
  1.7551 +  jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
  1.7552 +  RootedObject proto(cx, &slot.toObject());
  1.7553 +  JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
  1.7554 +
  1.7555 +  JSObject* result = Int64Base::Construct(cx, proto, i, false);
  1.7556 +  if (!result)
  1.7557 +    return false;
  1.7558 +
  1.7559 +  args.rval().setObject(*result);
  1.7560 +  return true;
  1.7561 +}
  1.7562 +
  1.7563 +bool
  1.7564 +UInt64::Construct(JSContext* cx,
  1.7565 +                  unsigned argc,
  1.7566 +                  jsval* vp)
  1.7567 +{
  1.7568 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7569 +
  1.7570 +  // Construct and return a new UInt64 object.
  1.7571 +  if (args.length() != 1) {
  1.7572 +    JS_ReportError(cx, "UInt64 takes one argument");
  1.7573 +    return false;
  1.7574 +  }
  1.7575 +
  1.7576 +  uint64_t u = 0;
  1.7577 +  if (!jsvalToBigInteger(cx, args[0], true, &u))
  1.7578 +    return TypeError(cx, "uint64", args[0]);
  1.7579 +
  1.7580 +  // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor.
  1.7581 +  RootedValue slot(cx);
  1.7582 +  RootedObject callee(cx, &args.callee());
  1.7583 +  ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
  1.7584 +  RootedObject proto(cx, &slot.toObject());
  1.7585 +  JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
  1.7586 +
  1.7587 +  JSObject* result = Int64Base::Construct(cx, proto, u, true);
  1.7588 +  if (!result)
  1.7589 +    return false;
  1.7590 +
  1.7591 +  args.rval().setObject(*result);
  1.7592 +  return true;
  1.7593 +}
  1.7594 +
  1.7595 +bool
  1.7596 +UInt64::IsUInt64(JSObject* obj)
  1.7597 +{
  1.7598 +  return JS_GetClass(obj) == &sUInt64Class;
  1.7599 +}
  1.7600 +
  1.7601 +bool
  1.7602 +UInt64::ToString(JSContext* cx, unsigned argc, jsval* vp)
  1.7603 +{
  1.7604 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7605 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.7606 +  if (!obj)
  1.7607 +    return false;
  1.7608 +  if (!UInt64::IsUInt64(obj)) {
  1.7609 +    JS_ReportError(cx, "not a UInt64");
  1.7610 +    return false;
  1.7611 +  }
  1.7612 +
  1.7613 +  return Int64Base::ToString(cx, obj, args, true);
  1.7614 +}
  1.7615 +
  1.7616 +bool
  1.7617 +UInt64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  1.7618 +{
  1.7619 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7620 +  JSObject* obj = JS_THIS_OBJECT(cx, vp);
  1.7621 +  if (!obj)
  1.7622 +    return false;
  1.7623 +  if (!UInt64::IsUInt64(obj)) {
  1.7624 +    JS_ReportError(cx, "not a UInt64");
  1.7625 +    return false;
  1.7626 +  }
  1.7627 +
  1.7628 +  return Int64Base::ToSource(cx, obj, args, true);
  1.7629 +}
  1.7630 +
  1.7631 +bool
  1.7632 +UInt64::Compare(JSContext* cx, unsigned argc, jsval* vp)
  1.7633 +{
  1.7634 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7635 +  if (args.length() != 2 ||
  1.7636 +      JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7637 +      JSVAL_IS_PRIMITIVE(args[1]) ||
  1.7638 +      !UInt64::IsUInt64(&args[0].toObject()) ||
  1.7639 +      !UInt64::IsUInt64(&args[1].toObject())) {
  1.7640 +    JS_ReportError(cx, "compare takes two UInt64 arguments");
  1.7641 +    return false;
  1.7642 +  }
  1.7643 +
  1.7644 +  JSObject* obj1 = &args[0].toObject();
  1.7645 +  JSObject* obj2 = &args[1].toObject();
  1.7646 +
  1.7647 +  uint64_t u1 = Int64Base::GetInt(obj1);
  1.7648 +  uint64_t u2 = Int64Base::GetInt(obj2);
  1.7649 +
  1.7650 +  if (u1 == u2)
  1.7651 +    args.rval().setInt32(0);
  1.7652 +  else if (u1 < u2)
  1.7653 +    args.rval().setInt32(-1);
  1.7654 +  else
  1.7655 +    args.rval().setInt32(1);
  1.7656 +
  1.7657 +  return true;
  1.7658 +}
  1.7659 +
  1.7660 +bool
  1.7661 +UInt64::Lo(JSContext* cx, unsigned argc, jsval* vp)
  1.7662 +{
  1.7663 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7664 +  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7665 +      !UInt64::IsUInt64(&args[0].toObject())) {
  1.7666 +    JS_ReportError(cx, "lo takes one UInt64 argument");
  1.7667 +    return false;
  1.7668 +  }
  1.7669 +
  1.7670 +  JSObject* obj = &args[0].toObject();
  1.7671 +  uint64_t u = Int64Base::GetInt(obj);
  1.7672 +  double d = uint32_t(INT64_LO(u));
  1.7673 +
  1.7674 +  args.rval().setDouble(d);
  1.7675 +  return true;
  1.7676 +}
  1.7677 +
  1.7678 +bool
  1.7679 +UInt64::Hi(JSContext* cx, unsigned argc, jsval* vp)
  1.7680 +{
  1.7681 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7682 +  if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  1.7683 +      !UInt64::IsUInt64(&args[0].toObject())) {
  1.7684 +    JS_ReportError(cx, "hi takes one UInt64 argument");
  1.7685 +    return false;
  1.7686 +  }
  1.7687 +
  1.7688 +  JSObject* obj = &args[0].toObject();
  1.7689 +  uint64_t u = Int64Base::GetInt(obj);
  1.7690 +  double d = uint32_t(INT64_HI(u));
  1.7691 +
  1.7692 +  args.rval().setDouble(d);
  1.7693 +  return true;
  1.7694 +}
  1.7695 +
  1.7696 +bool
  1.7697 +UInt64::Join(JSContext* cx, unsigned argc, jsval* vp)
  1.7698 +{
  1.7699 +  CallArgs args = CallArgsFromVp(argc, vp);
  1.7700 +  if (args.length() != 2) {
  1.7701 +    JS_ReportError(cx, "join takes two arguments");
  1.7702 +    return false;
  1.7703 +  }
  1.7704 +
  1.7705 +  uint32_t hi;
  1.7706 +  uint32_t lo;
  1.7707 +  if (!jsvalToInteger(cx, args[0], &hi))
  1.7708 +    return TypeError(cx, "uint32_t", args[0]);
  1.7709 +  if (!jsvalToInteger(cx, args[1], &lo))
  1.7710 +    return TypeError(cx, "uint32_t", args[1]);
  1.7711 +
  1.7712 +  uint64_t u = (uint64_t(hi) << 32) + uint64_t(lo);
  1.7713 +
  1.7714 +  // Get UInt64.prototype from the function's reserved slot.
  1.7715 +  JSObject* callee = &args.callee();
  1.7716 +
  1.7717 +  jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
  1.7718 +  RootedObject proto(cx, &slot.toObject());
  1.7719 +  JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
  1.7720 +
  1.7721 +  JSObject* result = Int64Base::Construct(cx, proto, u, true);
  1.7722 +  if (!result)
  1.7723 +    return false;
  1.7724 +
  1.7725 +  args.rval().setObject(*result);
  1.7726 +  return true;
  1.7727 +}
  1.7728 +
  1.7729 +}
  1.7730 +}

mercurial