js/src/ctypes/CTypes.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "ctypes/CTypes.h"
     9 #include "mozilla/FloatingPoint.h"
    10 #include "mozilla/MemoryReporting.h"
    11 #include "mozilla/NumericLimits.h"
    13 #include <math.h>
    14 #include <stdint.h>
    16 #if defined(XP_WIN)
    17 #include <float.h>
    18 #endif
    20 #if defined(SOLARIS)
    21 #include <ieeefp.h>
    22 #endif
    24 #ifdef HAVE_SSIZE_T
    25 #include <sys/types.h>
    26 #endif
    28 #if defined(XP_UNIX)
    29 #include <errno.h>
    30 #elif defined(XP_WIN)
    31 #include <windows.h>
    32 #endif
    34 #include "jscntxt.h"
    35 #include "jsfun.h"
    36 #include "jsnum.h"
    37 #include "jsprf.h"
    39 #include "builtin/TypedObject.h"
    40 #include "ctypes/Library.h"
    42 using namespace std;
    43 using mozilla::NumericLimits;
    45 namespace js {
    46 namespace ctypes {
    48 size_t
    49 GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
    50                             size_t nchars)
    51 {
    52     size_t nbytes;
    53     const jschar *end;
    54     unsigned c, c2;
    55     char buffer[10];
    57     nbytes = nchars;
    58     for (end = chars + nchars; chars != end; chars++) {
    59         c = *chars;
    60         if (c < 0x80)
    61             continue;
    62         if (0xD800 <= c && c <= 0xDFFF) {
    63             /* Surrogate pair. */
    64             chars++;
    66             /* nbytes sets 1 length since this is surrogate pair. */
    67             nbytes--;
    68             if (c >= 0xDC00 || chars == end)
    69                 goto bad_surrogate;
    70             c2 = *chars;
    71             if (c2 < 0xDC00 || c2 > 0xDFFF)
    72                 goto bad_surrogate;
    73             c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
    74         }
    75         c >>= 11;
    76         nbytes++;
    77         while (c) {
    78             c >>= 5;
    79             nbytes++;
    80         }
    81     }
    82     return nbytes;
    84   bad_surrogate:
    85     if (maybecx) {
    86         JS_snprintf(buffer, 10, "0x%x", c);
    87         JS_ReportErrorFlagsAndNumber(maybecx, JSREPORT_ERROR, js_GetErrorMessage,
    88                                      nullptr, JSMSG_BAD_SURROGATE_CHAR, buffer);
    89     }
    90     return (size_t) -1;
    91 }
    93 bool
    94 DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
    95                               char *dst, size_t *dstlenp)
    96 {
    97     size_t i, utf8Len;
    98     jschar c, c2;
    99     uint32_t v;
   100     uint8_t utf8buf[6];
   102     size_t dstlen = *dstlenp;
   103     size_t origDstlen = dstlen;
   105     while (srclen) {
   106         c = *src++;
   107         srclen--;
   108         if (c >= 0xDC00 && c <= 0xDFFF)
   109             goto badSurrogate;
   110         if (c < 0xD800 || c > 0xDBFF) {
   111             v = c;
   112         } else {
   113             if (srclen < 1)
   114                 goto badSurrogate;
   115             c2 = *src;
   116             if ((c2 < 0xDC00) || (c2 > 0xDFFF))
   117                 goto badSurrogate;
   118             src++;
   119             srclen--;
   120             v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
   121         }
   122         if (v < 0x0080) {
   123             /* no encoding necessary - performance hack */
   124             if (dstlen == 0)
   125                 goto bufferTooSmall;
   126             *dst++ = (char) v;
   127             utf8Len = 1;
   128         } else {
   129             utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v);
   130             if (utf8Len > dstlen)
   131                 goto bufferTooSmall;
   132             for (i = 0; i < utf8Len; i++)
   133                 *dst++ = (char) utf8buf[i];
   134         }
   135         dstlen -= utf8Len;
   136     }
   137     *dstlenp = (origDstlen - dstlen);
   138     return true;
   140 badSurrogate:
   141     *dstlenp = (origDstlen - dstlen);
   142     /* Delegate error reporting to the measurement function. */
   143     if (maybecx)
   144         GetDeflatedUTF8StringLength(maybecx, src - 1, srclen + 1);
   145     return false;
   147 bufferTooSmall:
   148     *dstlenp = (origDstlen - dstlen);
   149     if (maybecx) {
   150         JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr,
   151                              JSMSG_BUFFER_TOO_SMALL);
   152     }
   153     return false;
   154 }
   156 /*******************************************************************************
   157 ** JSAPI function prototypes
   158 *******************************************************************************/
   160 // We use an enclosing struct here out of paranoia about the ability of gcc 4.4
   161 // (and maybe 4.5) to correctly compile this if it were a template function.
   162 // See also the comments in dom/workers/Events.cpp (and other adjacent files) by
   163 // the |struct Property| there.
   164 template<JS::IsAcceptableThis Test, JS::NativeImpl Impl>
   165 struct Property
   166 {
   167   static bool
   168   Fun(JSContext* cx, unsigned argc, JS::Value* vp)
   169   {
   170     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   171     return JS::CallNonGenericMethod<Test, Impl>(cx, args);
   172   }
   173 };
   175 static bool ConstructAbstract(JSContext* cx, unsigned argc, jsval* vp);
   177 namespace CType {
   178   static bool ConstructData(JSContext* cx, unsigned argc, jsval* vp);
   179   static bool ConstructBasic(JSContext* cx, HandleObject obj, const CallArgs& args);
   181   static void Trace(JSTracer* trc, JSObject* obj);
   182   static void Finalize(JSFreeOp *fop, JSObject* obj);
   184   bool IsCType(HandleValue v);
   185   bool IsCTypeOrProto(HandleValue v);
   187   bool PrototypeGetter(JSContext* cx, JS::CallArgs args);
   188   bool NameGetter(JSContext* cx, JS::CallArgs args);
   189   bool SizeGetter(JSContext* cx, JS::CallArgs args);
   190   bool PtrGetter(JSContext* cx, JS::CallArgs args);
   192   static bool CreateArray(JSContext* cx, unsigned argc, jsval* vp);
   193   static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   194   static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   195   static bool HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp);
   198   /*
   199    * Get the global "ctypes" object.
   200    *
   201    * |obj| must be a CType object.
   202    *
   203    * This function never returns nullptr.
   204    */
   205   static JSObject* GetGlobalCTypes(JSContext* cx, JSObject* obj);
   207 }
   209 namespace ABI {
   210   bool IsABI(JSObject* obj);
   211   static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   212 }
   214 namespace PointerType {
   215   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   216   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   218   bool IsPointerType(HandleValue v);
   219   bool IsPointer(HandleValue v);
   221   bool TargetTypeGetter(JSContext* cx, JS::CallArgs args);
   222   bool ContentsGetter(JSContext* cx, JS::CallArgs args);
   223   bool ContentsSetter(JSContext* cx, JS::CallArgs args);
   225   static bool IsNull(JSContext* cx, unsigned argc, jsval* vp);
   226   static bool Increment(JSContext* cx, unsigned argc, jsval* vp);
   227   static bool Decrement(JSContext* cx, unsigned argc, jsval* vp);
   228   // The following is not an instance function, since we don't want to expose arbitrary
   229   // pointer arithmetic at this moment.
   230   static bool OffsetBy(JSContext* cx, const CallArgs& args, int offset);
   231 }
   233 namespace ArrayType {
   234   bool IsArrayType(HandleValue v);
   235   bool IsArrayOrArrayType(HandleValue v);
   237   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   238   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   240   bool ElementTypeGetter(JSContext* cx, JS::CallArgs args);
   241   bool LengthGetter(JSContext* cx, JS::CallArgs args);
   243   static bool Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp);
   244   static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp);
   245   static bool AddressOfElement(JSContext* cx, unsigned argc, jsval* vp);
   246 }
   248 namespace StructType {
   249   bool IsStruct(HandleValue v);
   251   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   252   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
   254   bool FieldsArrayGetter(JSContext* cx, JS::CallArgs args);
   256   static bool FieldGetter(JSContext* cx, HandleObject obj, HandleId idval,
   257     MutableHandleValue vp);
   258   static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
   259                             MutableHandleValue vp);
   260   static bool AddressOfField(JSContext* cx, unsigned argc, jsval* vp);
   261   static bool Define(JSContext* cx, unsigned argc, jsval* vp);
   262 }
   264 namespace FunctionType {
   265   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   266   static bool ConstructData(JSContext* cx, HandleObject typeObj,
   267     HandleObject dataObj, HandleObject fnObj, HandleObject thisObj, jsval errVal);
   269   static bool Call(JSContext* cx, unsigned argc, jsval* vp);
   271   bool IsFunctionType(HandleValue v);
   273   bool ArgTypesGetter(JSContext* cx, JS::CallArgs args);
   274   bool ReturnTypeGetter(JSContext* cx, JS::CallArgs args);
   275   bool ABIGetter(JSContext* cx, JS::CallArgs args);
   276   bool IsVariadicGetter(JSContext* cx, JS::CallArgs args);
   277 }
   279 namespace CClosure {
   280   static void Trace(JSTracer* trc, JSObject* obj);
   281   static void Finalize(JSFreeOp *fop, JSObject* obj);
   283   // libffi callback
   284   static void ClosureStub(ffi_cif* cif, void* result, void** args,
   285     void* userData);
   286 }
   288 namespace CData {
   289   static void Finalize(JSFreeOp *fop, JSObject* obj);
   291   bool ValueGetter(JSContext* cx, JS::CallArgs args);
   292   bool ValueSetter(JSContext* cx, JS::CallArgs args);
   294   static bool Address(JSContext* cx, unsigned argc, jsval* vp);
   295   static bool ReadString(JSContext* cx, unsigned argc, jsval* vp);
   296   static bool ReadStringReplaceMalformed(JSContext* cx, unsigned argc, jsval* vp);
   297   static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   298   static JSString *GetSourceString(JSContext *cx, HandleObject typeObj,
   299                                    void *data);
   301   bool ErrnoGetter(JSContext* cx, JS::CallArgs args);
   303 #if defined(XP_WIN)
   304   bool LastErrorGetter(JSContext* cx, JS::CallArgs args);
   305 #endif // defined(XP_WIN)
   306 }
   308 namespace CDataFinalizer {
   309   /*
   310    * Attach a C function as a finalizer to a JS object.
   311    *
   312    * This function is available from JS as |ctypes.withFinalizer|.
   313    *
   314    * JavaScript signature:
   315    * function(CData, CData):   CDataFinalizer
   316    *          value  finalizer finalizable
   317    *
   318    * Where |finalizer| is a one-argument function taking a value
   319    * with the same type as |value|.
   320    */
   321   static bool Construct(JSContext* cx, unsigned argc, jsval *vp);
   323   /*
   324    * Private data held by |CDataFinalizer|.
   325    *
   326    * See also |enum CDataFinalizerSlot| for the slots of
   327    * |CDataFinalizer|.
   328    *
   329    * Note: the private data may be nullptr, if |dispose|, |forget| or the
   330    * finalizer has already been called.
   331    */
   332   struct Private {
   333     /*
   334      * The C data to pass to the code.
   335      * Finalization/|dispose|/|forget| release this memory.
   336      */
   337     void *cargs;
   339     /*
   340      * The total size of the buffer pointed by |cargs|
   341      */
   342     size_t cargs_size;
   344     /*
   345      * Low-level signature information.
   346      * Finalization/|dispose|/|forget| release this memory.
   347      */
   348     ffi_cif CIF;
   350     /*
   351      * The C function to invoke during finalization.
   352      * Do not deallocate this.
   353      */
   354     uintptr_t code;
   356     /*
   357      * A buffer for holding the return value.
   358      * Finalization/|dispose|/|forget| release this memory.
   359      */
   360     void *rvalue;
   361   };
   363   /*
   364    * Methods of instances of |CDataFinalizer|
   365    */
   366   namespace Methods {
   367     static bool Dispose(JSContext* cx, unsigned argc, jsval *vp);
   368     static bool Forget(JSContext* cx, unsigned argc, jsval *vp);
   369     static bool ToSource(JSContext* cx, unsigned argc, jsval *vp);
   370     static bool ToString(JSContext* cx, unsigned argc, jsval *vp);
   371   }
   373   /*
   374    * Utility functions
   375    *
   376    * @return true if |obj| is a CDataFinalizer, false otherwise.
   377    */
   378   static bool IsCDataFinalizer(JSObject *obj);
   380   /*
   381    * Clean up the finalization information of a CDataFinalizer.
   382    *
   383    * Used by |Finalize|, |Dispose| and |Forget|.
   384    *
   385    * @param p The private information of the CDataFinalizer. If nullptr,
   386    * this function does nothing.
   387    * @param obj Either nullptr, if the object should not be cleaned up (i.e.
   388    * during finalization) or a CDataFinalizer JSObject. Always use nullptr
   389    * if you are calling from a finalizer.
   390    */
   391   static void Cleanup(Private *p, JSObject *obj);
   393   /*
   394    * Perform the actual call to the finalizer code.
   395    */
   396   static void CallFinalizer(CDataFinalizer::Private *p,
   397                             int* errnoStatus,
   398                             int32_t* lastErrorStatus);
   400   /*
   401    * Return the CType of a CDataFinalizer object, or nullptr if the object
   402    * has been cleaned-up already.
   403    */
   404   static JSObject *GetCType(JSContext *cx, JSObject *obj);
   406   /*
   407    * Perform finalization of a |CDataFinalizer|
   408    */
   409   static void Finalize(JSFreeOp *fop, JSObject *obj);
   411   /*
   412    * Return the jsval contained by this finalizer.
   413    *
   414    * Note that the jsval is actually not recorded, but converted back from C.
   415    */
   416   static bool GetValue(JSContext *cx, JSObject *obj, jsval *result);
   418   static JSObject* GetCData(JSContext *cx, JSObject *obj);
   419  }
   422 // Int64Base provides functions common to Int64 and UInt64.
   423 namespace Int64Base {
   424   JSObject* Construct(JSContext* cx, HandleObject proto, uint64_t data,
   425     bool isUnsigned);
   427   uint64_t GetInt(JSObject* obj);
   429   bool ToString(JSContext* cx, JSObject* obj, const CallArgs& args,
   430                 bool isUnsigned);
   432   bool ToSource(JSContext* cx, JSObject* obj, const CallArgs& args,
   433                 bool isUnsigned);
   435   static void Finalize(JSFreeOp *fop, JSObject* obj);
   436 }
   438 namespace Int64 {
   439   static bool Construct(JSContext* cx, unsigned argc, jsval* vp);
   441   static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   442   static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   444   static bool Compare(JSContext* cx, unsigned argc, jsval* vp);
   445   static bool Lo(JSContext* cx, unsigned argc, jsval* vp);
   446   static bool Hi(JSContext* cx, unsigned argc, jsval* vp);
   447   static bool Join(JSContext* cx, unsigned argc, jsval* vp);
   448 }
   450 namespace UInt64 {
   451   static bool Construct(JSContext* cx, unsigned argc, jsval* vp);
   453   static bool ToString(JSContext* cx, unsigned argc, jsval* vp);
   454   static bool ToSource(JSContext* cx, unsigned argc, jsval* vp);
   456   static bool Compare(JSContext* cx, unsigned argc, jsval* vp);
   457   static bool Lo(JSContext* cx, unsigned argc, jsval* vp);
   458   static bool Hi(JSContext* cx, unsigned argc, jsval* vp);
   459   static bool Join(JSContext* cx, unsigned argc, jsval* vp);
   460 }
   462 /*******************************************************************************
   463 ** JSClass definitions and initialization functions
   464 *******************************************************************************/
   466 // Class representing the 'ctypes' object itself. This exists to contain the
   467 // JSCTypesCallbacks set of function pointers.
   468 static const JSClass sCTypesGlobalClass = {
   469   "ctypes",
   470   JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS),
   471   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   472   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   473 };
   475 static const JSClass sCABIClass = {
   476   "CABI",
   477   JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS),
   478   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   479   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   480 };
   482 // Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype.
   483 // This exists to give said prototypes a class of "CType", and to provide
   484 // reserved slots for stashing various other prototype objects.
   485 static const JSClass sCTypeProtoClass = {
   486   "CType",
   487   JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
   488   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   489   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr,
   490   ConstructAbstract, nullptr, ConstructAbstract
   491 };
   493 // Class representing ctypes.CData.prototype and the 'prototype' properties
   494 // of CTypes. This exists to give said prototypes a class of "CData".
   495 static const JSClass sCDataProtoClass = {
   496   "CData",
   497   0,
   498   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   499   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   500 };
   502 static const JSClass sCTypeClass = {
   503   "CType",
   504   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
   505   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   506   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize,
   507   CType::ConstructData, CType::HasInstance, CType::ConstructData,
   508   CType::Trace
   509 };
   511 static const JSClass sCDataClass = {
   512   "CData",
   513   JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
   514   JS_PropertyStub, JS_DeletePropertyStub, ArrayType::Getter, ArrayType::Setter,
   515   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize,
   516   FunctionType::Call, nullptr, FunctionType::Call
   517 };
   519 static const JSClass sCClosureClass = {
   520   "CClosure",
   521   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
   522   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   523   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize,
   524   nullptr, nullptr, nullptr, CClosure::Trace
   525 };
   527 /*
   528  * Class representing the prototype of CDataFinalizer.
   529  */
   530 static const JSClass sCDataFinalizerProtoClass = {
   531   "CDataFinalizer",
   532   0,
   533   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   534   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   535 };
   537 /*
   538  * Class representing instances of CDataFinalizer.
   539  *
   540  * Instances of CDataFinalizer have both private data (with type
   541  * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|).
   542  */
   543 static const JSClass sCDataFinalizerClass = {
   544   "CDataFinalizer",
   545   JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS),
   546   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   547   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CDataFinalizer::Finalize,
   548 };
   551 #define CTYPESFN_FLAGS \
   552   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
   554 #define CTYPESCTOR_FLAGS \
   555   (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR)
   557 #define CTYPESACC_FLAGS \
   558   (JSPROP_ENUMERATE | JSPROP_PERMANENT)
   560 #define CABIFN_FLAGS \
   561   (JSPROP_READONLY | JSPROP_PERMANENT)
   563 #define CDATAFN_FLAGS \
   564   (JSPROP_READONLY | JSPROP_PERMANENT)
   566 #define CDATAFINALIZERFN_FLAGS \
   567   (JSPROP_READONLY | JSPROP_PERMANENT)
   569 static const JSPropertySpec sCTypeProps[] = {
   570   JS_PSG("name",
   571          (Property<CType::IsCType, CType::NameGetter>::Fun),
   572          CTYPESACC_FLAGS),
   573   JS_PSG("size",
   574          (Property<CType::IsCType, CType::SizeGetter>::Fun),
   575          CTYPESACC_FLAGS),
   576   JS_PSG("ptr",
   577          (Property<CType::IsCType, CType::PtrGetter>::Fun),
   578          CTYPESACC_FLAGS),
   579   JS_PSG("prototype",
   580          (Property<CType::IsCTypeOrProto, CType::PrototypeGetter>::Fun),
   581          CTYPESACC_FLAGS),
   582   JS_PS_END
   583 };
   585 static const JSFunctionSpec sCTypeFunctions[] = {
   586   JS_FN("array", CType::CreateArray, 0, CTYPESFN_FLAGS),
   587   JS_FN("toString", CType::ToString, 0, CTYPESFN_FLAGS),
   588   JS_FN("toSource", CType::ToSource, 0, CTYPESFN_FLAGS),
   589   JS_FS_END
   590 };
   592 static const JSFunctionSpec sCABIFunctions[] = {
   593   JS_FN("toSource", ABI::ToSource, 0, CABIFN_FLAGS),
   594   JS_FN("toString", ABI::ToSource, 0, CABIFN_FLAGS),
   595   JS_FS_END
   596 };
   598 static const JSPropertySpec sCDataProps[] = {
   599   JS_PSGS("value",
   600           (Property<CData::IsCData, CData::ValueGetter>::Fun),
   601           (Property<CData::IsCData, CData::ValueSetter>::Fun),
   602           JSPROP_PERMANENT),
   603   JS_PS_END
   604 };
   606 static const JSFunctionSpec sCDataFunctions[] = {
   607   JS_FN("address", CData::Address, 0, CDATAFN_FLAGS),
   608   JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS),
   609   JS_FN("readStringReplaceMalformed", CData::ReadStringReplaceMalformed, 0, CDATAFN_FLAGS),
   610   JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS),
   611   JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS),
   612   JS_FS_END
   613 };
   615 static const JSFunctionSpec sCDataFinalizerFunctions[] = {
   616   JS_FN("dispose",  CDataFinalizer::Methods::Dispose,  0, CDATAFINALIZERFN_FLAGS),
   617   JS_FN("forget",   CDataFinalizer::Methods::Forget,   0, CDATAFINALIZERFN_FLAGS),
   618   JS_FN("readString",CData::ReadString, 0, CDATAFINALIZERFN_FLAGS),
   619   JS_FN("toString", CDataFinalizer::Methods::ToString, 0, CDATAFINALIZERFN_FLAGS),
   620   JS_FN("toSource", CDataFinalizer::Methods::ToSource, 0, CDATAFINALIZERFN_FLAGS),
   621   JS_FS_END
   622 };
   624 static const JSFunctionSpec sPointerFunction =
   625   JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS);
   627 static const JSPropertySpec sPointerProps[] = {
   628   JS_PSG("targetType",
   629          (Property<PointerType::IsPointerType, PointerType::TargetTypeGetter>::Fun),
   630          CTYPESACC_FLAGS),
   631   JS_PS_END
   632 };
   634 static const JSFunctionSpec sPointerInstanceFunctions[] = {
   635   JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS),
   636   JS_FN("increment", PointerType::Increment, 0, CTYPESFN_FLAGS),
   637   JS_FN("decrement", PointerType::Decrement, 0, CTYPESFN_FLAGS),
   638   JS_FS_END
   639 };
   641 static const JSPropertySpec sPointerInstanceProps[] = {
   642   JS_PSGS("contents",
   643          (Property<PointerType::IsPointer, PointerType::ContentsGetter>::Fun),
   644          (Property<PointerType::IsPointer, PointerType::ContentsSetter>::Fun),
   645           JSPROP_PERMANENT),
   646   JS_PS_END
   647 };
   649 static const JSFunctionSpec sArrayFunction =
   650   JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS);
   652 static const JSPropertySpec sArrayProps[] = {
   653   JS_PSG("elementType",
   654          (Property<ArrayType::IsArrayType, ArrayType::ElementTypeGetter>::Fun),
   655          CTYPESACC_FLAGS),
   656   JS_PSG("length",
   657          (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
   658          CTYPESACC_FLAGS),
   659   JS_PS_END
   660 };
   662 static const JSFunctionSpec sArrayInstanceFunctions[] = {
   663   JS_FN("addressOfElement", ArrayType::AddressOfElement, 1, CDATAFN_FLAGS),
   664   JS_FS_END
   665 };
   667 static const JSPropertySpec sArrayInstanceProps[] = {
   668   JS_PSG("length",
   669          (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
   670          JSPROP_PERMANENT),
   671   JS_PS_END
   672 };
   674 static const JSFunctionSpec sStructFunction =
   675   JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS);
   677 static const JSPropertySpec sStructProps[] = {
   678   JS_PSG("fields",
   679          (Property<StructType::IsStruct, StructType::FieldsArrayGetter>::Fun),
   680          CTYPESACC_FLAGS),
   681   JS_PS_END
   682 };
   684 static const JSFunctionSpec sStructFunctions[] = {
   685   JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS),
   686   JS_FS_END
   687 };
   689 static const JSFunctionSpec sStructInstanceFunctions[] = {
   690   JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS),
   691   JS_FS_END
   692 };
   694 static const JSFunctionSpec sFunctionFunction =
   695   JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS);
   697 static const JSPropertySpec sFunctionProps[] = {
   698   JS_PSG("argTypes",
   699          (Property<FunctionType::IsFunctionType, FunctionType::ArgTypesGetter>::Fun),
   700          CTYPESACC_FLAGS),
   701   JS_PSG("returnType",
   702          (Property<FunctionType::IsFunctionType, FunctionType::ReturnTypeGetter>::Fun),
   703          CTYPESACC_FLAGS),
   704   JS_PSG("abi",
   705          (Property<FunctionType::IsFunctionType, FunctionType::ABIGetter>::Fun),
   706          CTYPESACC_FLAGS),
   707   JS_PSG("isVariadic",
   708          (Property<FunctionType::IsFunctionType, FunctionType::IsVariadicGetter>::Fun),
   709          CTYPESACC_FLAGS),
   710   JS_PS_END
   711 };
   713 static const JSFunctionSpec sFunctionInstanceFunctions[] = {
   714   JS_FN("call", js_fun_call, 1, CDATAFN_FLAGS),
   715   JS_FN("apply", js_fun_apply, 2, CDATAFN_FLAGS),
   716   JS_FS_END
   717 };
   719 static const JSClass sInt64ProtoClass = {
   720   "Int64",
   721   0,
   722   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   723   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   724 };
   726 static const JSClass sUInt64ProtoClass = {
   727   "UInt64",
   728   0,
   729   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   730   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
   731 };
   733 static const JSClass sInt64Class = {
   734   "Int64",
   735   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
   736   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   737   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
   738 };
   740 static const JSClass sUInt64Class = {
   741   "UInt64",
   742   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
   743   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   744   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
   745 };
   747 static const JSFunctionSpec sInt64StaticFunctions[] = {
   748   JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS),
   749   JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS),
   750   JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS),
   751   JS_FN("join", Int64::Join, 2, CTYPESFN_FLAGS),
   752   JS_FS_END
   753 };
   755 static const JSFunctionSpec sUInt64StaticFunctions[] = {
   756   JS_FN("compare", UInt64::Compare, 2, CTYPESFN_FLAGS),
   757   JS_FN("lo", UInt64::Lo, 1, CTYPESFN_FLAGS),
   758   JS_FN("hi", UInt64::Hi, 1, CTYPESFN_FLAGS),
   759   JS_FN("join", UInt64::Join, 2, CTYPESFN_FLAGS),
   760   JS_FS_END
   761 };
   763 static const JSFunctionSpec sInt64Functions[] = {
   764   JS_FN("toString", Int64::ToString, 0, CTYPESFN_FLAGS),
   765   JS_FN("toSource", Int64::ToSource, 0, CTYPESFN_FLAGS),
   766   JS_FS_END
   767 };
   769 static const JSFunctionSpec sUInt64Functions[] = {
   770   JS_FN("toString", UInt64::ToString, 0, CTYPESFN_FLAGS),
   771   JS_FN("toSource", UInt64::ToSource, 0, CTYPESFN_FLAGS),
   772   JS_FS_END
   773 };
   775 static const JSPropertySpec sModuleProps[] = {
   776   JS_PSG("errno",
   777          (Property<IsCTypesGlobal, CData::ErrnoGetter>::Fun),
   778          JSPROP_PERMANENT),
   779 #if defined(XP_WIN)
   780   JS_PSG("winLastError",
   781          (Property<IsCTypesGlobal, CData::LastErrorGetter>::Fun),
   782          JSPROP_PERMANENT),
   783 #endif // defined(XP_WIN)
   784   JS_PS_END
   785 };
   787 static const JSFunctionSpec sModuleFunctions[] = {
   788   JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS),
   789   JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
   790   JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
   791   JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
   792   JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
   793   JS_FS_END
   794 };
   796 static MOZ_ALWAYS_INLINE JSString*
   797 NewUCString(JSContext* cx, const AutoString& from)
   798 {
   799   return JS_NewUCStringCopyN(cx, from.begin(), from.length());
   800 }
   802 /*
   803  * Return a size rounded up to a multiple of a power of two.
   804  *
   805  * Note: |align| must be a power of 2.
   806  */
   807 static MOZ_ALWAYS_INLINE size_t
   808 Align(size_t val, size_t align)
   809 {
   810   // Ensure that align is a power of two.
   811   MOZ_ASSERT(align != 0 && (align & (align - 1)) == 0);
   812   return ((val - 1) | (align - 1)) + 1;
   813 }
   815 static ABICode
   816 GetABICode(JSObject* obj)
   817 {
   818   // make sure we have an object representing a CABI class,
   819   // and extract the enumerated class type from the reserved slot.
   820   if (JS_GetClass(obj) != &sCABIClass)
   821     return INVALID_ABI;
   823   jsval result = JS_GetReservedSlot(obj, SLOT_ABICODE);
   824   return ABICode(JSVAL_TO_INT(result));
   825 }
   827 static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
   828 #define MSG_DEF(name, number, count, exception, format) \
   829   { format, count, exception } ,
   830 #include "ctypes/ctypes.msg"
   831 #undef MSG_DEF
   832 };
   834 static const JSErrorFormatString*
   835 GetErrorMessage(void* userRef, const char* locale, const unsigned errorNumber)
   836 {
   837   if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
   838     return &ErrorFormatString[errorNumber];
   839   return nullptr;
   840 }
   842 static bool
   843 TypeError(JSContext* cx, const char* expected, HandleValue actual)
   844 {
   845   JSString* str = JS_ValueToSource(cx, actual);
   846   JSAutoByteString bytes;
   848   const char* src;
   849   if (str) {
   850     src = bytes.encodeLatin1(cx, str);
   851     if (!src)
   852       return false;
   853   } else {
   854     JS_ClearPendingException(cx);
   855     src = "<<error converting value to string>>";
   856   }
   857   JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
   858                        CTYPESMSG_TYPE_ERROR, expected, src);
   859   return false;
   860 }
   862 static JSObject*
   863 InitCTypeClass(JSContext* cx, HandleObject parent)
   864 {
   865   JSFunction *fun = JS_DefineFunction(cx, parent, "CType", ConstructAbstract, 0,
   866                                       CTYPESCTOR_FLAGS);
   867   if (!fun)
   868     return nullptr;
   870   RootedObject ctor(cx, JS_GetFunctionObject(fun));
   871   RootedObject fnproto(cx);
   872   if (!JS_GetPrototype(cx, ctor, &fnproto))
   873     return nullptr;
   874   JS_ASSERT(ctor);
   875   JS_ASSERT(fnproto);
   877   // Set up ctypes.CType.prototype.
   878   RootedObject prototype(cx, JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent));
   879   if (!prototype)
   880     return nullptr;
   882   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
   883                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   884     return nullptr;
   886   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
   887                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   888     return nullptr;
   890   // Define properties and functions common to all CTypes.
   891   if (!JS_DefineProperties(cx, prototype, sCTypeProps) ||
   892       !JS_DefineFunctions(cx, prototype, sCTypeFunctions))
   893     return nullptr;
   895   if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
   896     return nullptr;
   898   return prototype;
   899 }
   901 static JSObject*
   902 InitABIClass(JSContext* cx, JSObject* parent)
   903 {
   904   RootedObject obj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
   906   if (!obj)
   907     return nullptr;
   909   if (!JS_DefineFunctions(cx, obj, sCABIFunctions))
   910     return nullptr;
   912   return obj;
   913 }
   916 static JSObject*
   917 InitCDataClass(JSContext* cx, HandleObject parent, HandleObject CTypeProto)
   918 {
   919   JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0,
   920                       CTYPESCTOR_FLAGS);
   921   if (!fun)
   922     return nullptr;
   924   RootedObject ctor(cx, JS_GetFunctionObject(fun));
   925   JS_ASSERT(ctor);
   927   // Set up ctypes.CData.__proto__ === ctypes.CType.prototype.
   928   // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the
   929   // prototype chain.)
   930   if (!JS_SetPrototype(cx, ctor, CTypeProto))
   931     return nullptr;
   933   // Set up ctypes.CData.prototype.
   934   RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, NullPtr(), parent));
   935   if (!prototype)
   936     return nullptr;
   938   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
   939                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   940     return nullptr;
   942   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
   943                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
   944     return nullptr;
   946   // Define properties and functions common to all CDatas.
   947   if (!JS_DefineProperties(cx, prototype, sCDataProps) ||
   948       !JS_DefineFunctions(cx, prototype, sCDataFunctions))
   949     return nullptr;
   951   if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
   952       !JS_FreezeObject(cx, ctor))
   953     return nullptr;
   955   return prototype;
   956 }
   958 static bool
   959 DefineABIConstant(JSContext* cx,
   960                   HandleObject parent,
   961                   const char* name,
   962                   ABICode code,
   963                   HandleObject prototype)
   964 {
   965   RootedObject obj(cx, JS_DefineObject(cx, parent, name, &sCABIClass, prototype,
   966                                        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT));
   967   if (!obj)
   968     return false;
   969   JS_SetReservedSlot(obj, SLOT_ABICODE, INT_TO_JSVAL(code));
   970   return JS_FreezeObject(cx, obj);
   971 }
   973 // Set up a single type constructor for
   974 // ctypes.{Pointer,Array,Struct,Function}Type.
   975 static bool
   976 InitTypeConstructor(JSContext* cx,
   977                     HandleObject parent,
   978                     HandleObject CTypeProto,
   979                     HandleObject CDataProto,
   980                     const JSFunctionSpec spec,
   981                     const JSFunctionSpec* fns,
   982                     const JSPropertySpec* props,
   983                     const JSFunctionSpec* instanceFns,
   984                     const JSPropertySpec* instanceProps,
   985                     MutableHandleObject typeProto,
   986                     MutableHandleObject dataProto)
   987 {
   988   JSFunction* fun = js::DefineFunctionWithReserved(cx, parent, spec.name, spec.call.op,
   989                       spec.nargs, spec.flags);
   990   if (!fun)
   991     return false;
   993   RootedObject obj(cx, JS_GetFunctionObject(fun));
   994   if (!obj)
   995     return false;
   997   // Set up the .prototype and .prototype.constructor properties.
   998   typeProto.set(JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent));
   999   if (!typeProto)
  1000     return false;
  1002   // Define property before proceeding, for GC safety.
  1003   if (!JS_DefineProperty(cx, obj, "prototype", typeProto,
  1004                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1005     return false;
  1007   if (fns && !JS_DefineFunctions(cx, typeProto, fns))
  1008     return false;
  1010   if (!JS_DefineProperties(cx, typeProto, props))
  1011     return false;
  1013   if (!JS_DefineProperty(cx, typeProto, "constructor", obj,
  1014                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1015     return false;
  1017   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
  1018   // the type constructor, for faster lookup.
  1019   js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
  1021   // Create an object to serve as the common ancestor for all CData objects
  1022   // created from the given type constructor. This has ctypes.CData.prototype
  1023   // as its prototype, such that it inherits the properties and functions
  1024   // common to all CDatas.
  1025   dataProto.set(JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent));
  1026   if (!dataProto)
  1027     return false;
  1029   // Define functions and properties on the 'dataProto' object that are common
  1030   // to all CData objects created from this type constructor. (These will
  1031   // become functions and properties on CData objects created from this type.)
  1032   if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns))
  1033     return false;
  1035   if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps))
  1036     return false;
  1038   // Link the type prototype to the data prototype.
  1039   JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(dataProto));
  1041   if (!JS_FreezeObject(cx, obj) ||
  1042       //!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
  1043       !JS_FreezeObject(cx, typeProto))
  1044     return false;
  1046   return true;
  1049 static JSObject*
  1050 InitInt64Class(JSContext* cx,
  1051                HandleObject parent,
  1052                const JSClass* clasp,
  1053                JSNative construct,
  1054                const JSFunctionSpec* fs,
  1055                const JSFunctionSpec* static_fs)
  1057   // Init type class and constructor
  1058   RootedObject prototype(cx, JS_InitClass(cx, parent, js::NullPtr(), clasp, construct,
  1059                                           0, nullptr, fs, nullptr, static_fs));
  1060   if (!prototype)
  1061     return nullptr;
  1063   RootedObject ctor(cx, JS_GetConstructor(cx, prototype));
  1064   if (!ctor)
  1065     return nullptr;
  1066   if (!JS_FreezeObject(cx, ctor))
  1067     return nullptr;
  1069   // Redefine the 'join' function as an extended native and stash
  1070   // ctypes.{Int64,UInt64}.prototype in a reserved slot of the new function.
  1071   JS_ASSERT(clasp == &sInt64ProtoClass || clasp == &sUInt64ProtoClass);
  1072   JSNative native = (clasp == &sInt64ProtoClass) ? Int64::Join : UInt64::Join;
  1073   JSFunction* fun = js::DefineFunctionWithReserved(cx, ctor, "join", native,
  1074                       2, CTYPESFN_FLAGS);
  1075   if (!fun)
  1076     return nullptr;
  1078   js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO,
  1079     OBJECT_TO_JSVAL(prototype));
  1081   if (!JS_FreezeObject(cx, prototype))
  1082     return nullptr;
  1084   return prototype;
  1087 static void
  1088 AttachProtos(JSObject* proto, const AutoObjectVector& protos)
  1090   // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos'
  1091   // to the appropriate CTypeProtoSlot. (SLOT_CTYPES is the last slot
  1092   // of [[Class]] "CTypeProto" that we fill in this automated manner.)
  1093   for (uint32_t i = 0; i <= SLOT_CTYPES; ++i)
  1094     JS_SetReservedSlot(proto, i, OBJECT_TO_JSVAL(protos[i]));
  1097 static bool
  1098 InitTypeClasses(JSContext* cx, HandleObject parent)
  1100   // Initialize the ctypes.CType class. This acts as an abstract base class for
  1101   // the various types, and provides the common API functions. It has:
  1102   //   * [[Class]] "Function"
  1103   //   * __proto__ === Function.prototype
  1104   //   * A constructor that throws a TypeError. (You can't construct an
  1105   //     abstract type!)
  1106   //   * 'prototype' property:
  1107   //     * [[Class]] "CTypeProto"
  1108   //     * __proto__ === Function.prototype
  1109   //     * A constructor that throws a TypeError. (You can't construct an
  1110   //       abstract type instance!)
  1111   //     * 'constructor' property === ctypes.CType
  1112   //     * Provides properties and functions common to all CTypes.
  1113   RootedObject CTypeProto(cx, InitCTypeClass(cx, parent));
  1114   if (!CTypeProto)
  1115     return false;
  1117   // Initialize the ctypes.CData class. This acts as an abstract base class for
  1118   // instances of the various types, and provides the common API functions.
  1119   // It has:
  1120   //   * [[Class]] "Function"
  1121   //   * __proto__ === Function.prototype
  1122   //   * A constructor that throws a TypeError. (You can't construct an
  1123   //     abstract type instance!)
  1124   //   * 'prototype' property:
  1125   //     * [[Class]] "CDataProto"
  1126   //     * 'constructor' property === ctypes.CData
  1127   //     * Provides properties and functions common to all CDatas.
  1128   RootedObject CDataProto(cx, InitCDataClass(cx, parent, CTypeProto));
  1129   if (!CDataProto)
  1130     return false;
  1132   // Link CTypeProto to CDataProto.
  1133   JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(CDataProto));
  1135   // Create and attach the special class constructors: ctypes.PointerType,
  1136   // ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType.
  1137   // Each of these constructors 'c' has, respectively:
  1138   //   * [[Class]] "Function"
  1139   //   * __proto__ === Function.prototype
  1140   //   * A constructor that creates a user-defined type.
  1141   //   * 'prototype' property:
  1142   //     * [[Class]] "CTypeProto"
  1143   //     * __proto__ === ctypes.CType.prototype
  1144   //     * 'constructor' property === 'c'
  1145   // We also construct an object 'p' to serve, given a type object 't'
  1146   // constructed from one of these type constructors, as
  1147   // 't.prototype.__proto__'. This object has:
  1148   //   * [[Class]] "CDataProto"
  1149   //   * __proto__ === ctypes.CData.prototype
  1150   //   * Properties and functions common to all CDatas.
  1151   // Therefore an instance 't' of ctypes.{Pointer,Array,Struct,Function}Type
  1152   // will have, resp.:
  1153   //   * [[Class]] "CType"
  1154   //   * __proto__ === ctypes.{Pointer,Array,Struct,Function}Type.prototype
  1155   //   * A constructor which creates and returns a CData object, containing
  1156   //     binary data of the given type.
  1157   //   * 'prototype' property:
  1158   //     * [[Class]] "CDataProto"
  1159   //     * __proto__ === 'p', the prototype object from above
  1160   //     * 'constructor' property === 't'
  1161   AutoObjectVector protos(cx);
  1162   protos.resize(CTYPEPROTO_SLOTS);
  1163   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1164          sPointerFunction, nullptr, sPointerProps,
  1165          sPointerInstanceFunctions, sPointerInstanceProps,
  1166          protos.handleAt(SLOT_POINTERPROTO), protos.handleAt(SLOT_POINTERDATAPROTO)))
  1167     return false;
  1169   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1170          sArrayFunction, nullptr, sArrayProps,
  1171          sArrayInstanceFunctions, sArrayInstanceProps,
  1172          protos.handleAt(SLOT_ARRAYPROTO), protos.handleAt(SLOT_ARRAYDATAPROTO)))
  1173     return false;
  1175   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
  1176          sStructFunction, sStructFunctions, sStructProps,
  1177          sStructInstanceFunctions, nullptr,
  1178          protos.handleAt(SLOT_STRUCTPROTO), protos.handleAt(SLOT_STRUCTDATAPROTO)))
  1179     return false;
  1181   if (!InitTypeConstructor(cx, parent, CTypeProto, protos.handleAt(SLOT_POINTERDATAPROTO),
  1182          sFunctionFunction, nullptr, sFunctionProps, sFunctionInstanceFunctions, nullptr,
  1183          protos.handleAt(SLOT_FUNCTIONPROTO), protos.handleAt(SLOT_FUNCTIONDATAPROTO)))
  1184     return false;
  1186   protos[SLOT_CDATAPROTO] = CDataProto;
  1188   // Create and attach the ctypes.{Int64,UInt64} constructors.
  1189   // Each of these has, respectively:
  1190   //   * [[Class]] "Function"
  1191   //   * __proto__ === Function.prototype
  1192   //   * A constructor that creates a ctypes.{Int64,UInt64} object, respectively.
  1193   //   * 'prototype' property:
  1194   //     * [[Class]] {"Int64Proto","UInt64Proto"}
  1195   //     * 'constructor' property === ctypes.{Int64,UInt64}
  1196   protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass,
  1197     Int64::Construct, sInt64Functions, sInt64StaticFunctions);
  1198   if (!protos[SLOT_INT64PROTO])
  1199     return false;
  1200   protos[SLOT_UINT64PROTO] = InitInt64Class(cx, parent, &sUInt64ProtoClass,
  1201     UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions);
  1202   if (!protos[SLOT_UINT64PROTO])
  1203     return false;
  1205   // Finally, store a pointer to the global ctypes object.
  1206   // Note that there is no other reliable manner of locating this object.
  1207   protos[SLOT_CTYPES] = parent;
  1209   // Attach the prototypes just created to each of ctypes.CType.prototype,
  1210   // and the special type constructors, so we can access them when constructing
  1211   // instances of those types.
  1212   AttachProtos(CTypeProto, protos);
  1213   AttachProtos(protos[SLOT_POINTERPROTO], protos);
  1214   AttachProtos(protos[SLOT_ARRAYPROTO], protos);
  1215   AttachProtos(protos[SLOT_STRUCTPROTO], protos);
  1216   AttachProtos(protos[SLOT_FUNCTIONPROTO], protos);
  1218   RootedObject ABIProto(cx, InitABIClass(cx, parent));
  1219   if (!ABIProto)
  1220     return false;
  1222   // Attach objects representing ABI constants.
  1223   if (!DefineABIConstant(cx, parent, "default_abi", ABI_DEFAULT, ABIProto) ||
  1224       !DefineABIConstant(cx, parent, "stdcall_abi", ABI_STDCALL, ABIProto) ||
  1225       !DefineABIConstant(cx, parent, "winapi_abi", ABI_WINAPI, ABIProto))
  1226     return false;
  1228   // Create objects representing the builtin types, and attach them to the
  1229   // ctypes object. Each type object 't' has:
  1230   //   * [[Class]] "CType"
  1231   //   * __proto__ === ctypes.CType.prototype
  1232   //   * A constructor which creates and returns a CData object, containing
  1233   //     binary data of the given type.
  1234   //   * 'prototype' property:
  1235   //     * [[Class]] "CDataProto"
  1236   //     * __proto__ === ctypes.CData.prototype
  1237   //     * 'constructor' property === 't'
  1238 #define DEFINE_TYPE(name, type, ffiType)                                       \
  1239   RootedObject typeObj_##name(cx,                                              \
  1240     CType::DefineBuiltin(cx, parent, #name, CTypeProto, CDataProto, #name,     \
  1241       TYPE_##name, INT_TO_JSVAL(sizeof(type)),                                 \
  1242       INT_TO_JSVAL(ffiType.alignment), &ffiType));                             \
  1243   if (!typeObj_##name)                                                         \
  1244     return false;
  1245 #include "ctypes/typedefs.h"
  1247   // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
  1248   // the same type in C.
  1249   if (!JS_DefineProperty(cx, parent, "unsigned", typeObj_unsigned_int,
  1250                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1251     return false;
  1253   // Create objects representing the special types void_t and voidptr_t.
  1254   RootedObject typeObj(cx,
  1255     CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void",
  1256                          TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void));
  1257   if (!typeObj)
  1258     return false;
  1260   typeObj = PointerType::CreateInternal(cx, typeObj);
  1261   if (!typeObj)
  1262     return false;
  1263   if (!JS_DefineProperty(cx, parent, "voidptr_t", typeObj,
  1264                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1265     return false;
  1267   return true;
  1270 bool
  1271 IsCTypesGlobal(JSObject* obj)
  1273   return JS_GetClass(obj) == &sCTypesGlobalClass;
  1276 bool
  1277 IsCTypesGlobal(HandleValue v)
  1279   return v.isObject() && IsCTypesGlobal(&v.toObject());
  1282 // Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'.
  1283 JSCTypesCallbacks*
  1284 GetCallbacks(JSObject* obj)
  1286   JS_ASSERT(IsCTypesGlobal(obj));
  1288   jsval result = JS_GetReservedSlot(obj, SLOT_CALLBACKS);
  1289   if (JSVAL_IS_VOID(result))
  1290     return nullptr;
  1292   return static_cast<JSCTypesCallbacks*>(JSVAL_TO_PRIVATE(result));
  1295 // Utility function to access a property of an object as an object
  1296 // returns false and sets the error if the property does not exist
  1297 // or is not an object
  1298 static bool GetObjectProperty(JSContext *cx, HandleObject obj,
  1299                               const char *property, MutableHandleObject result)
  1301   RootedValue val(cx);
  1302   if (!JS_GetProperty(cx, obj, property, &val)) {
  1303     return false;
  1306   if (JSVAL_IS_PRIMITIVE(val)) {
  1307     JS_ReportError(cx, "missing or non-object field");
  1308     return false;
  1311   result.set(JSVAL_TO_OBJECT(val));
  1312   return true;
  1315 } /* namespace ctypes */
  1316 } /* namespace js */
  1318 using namespace js;
  1319 using namespace js::ctypes;
  1321 JS_PUBLIC_API(bool)
  1322 JS_InitCTypesClass(JSContext* cx, HandleObject global)
  1324   // attach ctypes property to global object
  1325   RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass, NullPtr(), NullPtr()));
  1326   if (!ctypes)
  1327     return false;
  1329   if (!JS_DefineProperty(cx, global, "ctypes", ctypes, JSPROP_READONLY | JSPROP_PERMANENT,
  1330                          JS_PropertyStub, JS_StrictPropertyStub)){
  1331     return false;
  1334   if (!InitTypeClasses(cx, ctypes))
  1335     return false;
  1337   // attach API functions and properties
  1338   if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions) ||
  1339       !JS_DefineProperties(cx, ctypes, sModuleProps))
  1340     return false;
  1342   // Set up ctypes.CDataFinalizer.prototype.
  1343   RootedObject ctor(cx);
  1344   if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor))
  1345     return false;
  1347   RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, NullPtr(), ctypes));
  1348   if (!prototype)
  1349     return false;
  1351   if (!JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions))
  1352     return false;
  1354   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
  1355                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1356     return false;
  1358   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
  1359                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  1360     return false;
  1363   // Seal the ctypes object, to prevent modification.
  1364   return JS_FreezeObject(cx, ctypes);
  1367 JS_PUBLIC_API(void)
  1368 JS_SetCTypesCallbacks(JSObject *ctypesObj, JSCTypesCallbacks* callbacks)
  1370   JS_ASSERT(callbacks);
  1371   JS_ASSERT(IsCTypesGlobal(ctypesObj));
  1373   // Set the callbacks on a reserved slot.
  1374   JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS, PRIVATE_TO_JSVAL(callbacks));
  1377 namespace js {
  1379 JS_FRIEND_API(size_t)
  1380 SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject *obj)
  1382     if (!CData::IsCData(obj))
  1383         return 0;
  1385     size_t n = 0;
  1386     jsval slot = JS_GetReservedSlot(obj, ctypes::SLOT_OWNS);
  1387     if (!JSVAL_IS_VOID(slot)) {
  1388         bool owns = JSVAL_TO_BOOLEAN(slot);
  1389         slot = JS_GetReservedSlot(obj, ctypes::SLOT_DATA);
  1390         if (!JSVAL_IS_VOID(slot)) {
  1391             char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
  1392             n += mallocSizeOf(buffer);
  1393             if (owns)
  1394                 n += mallocSizeOf(*buffer);
  1397     return n;
  1400 namespace ctypes {
  1402 /*******************************************************************************
  1403 ** Type conversion functions
  1404 *******************************************************************************/
  1406 // Enforce some sanity checks on type widths and properties.
  1407 // Where the architecture is 64-bit, make sure it's LP64 or LLP64. (ctypes.int
  1408 // autoconverts to a primitive JS number; to support ILP64 architectures, it
  1409 // would need to autoconvert to an Int64 object instead. Therefore we enforce
  1410 // this invariant here.)
  1411 JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4);
  1412 JS_STATIC_ASSERT(sizeof(char) == 1);
  1413 JS_STATIC_ASSERT(sizeof(short) == 2);
  1414 JS_STATIC_ASSERT(sizeof(int) == 4);
  1415 JS_STATIC_ASSERT(sizeof(unsigned) == 4);
  1416 JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
  1417 JS_STATIC_ASSERT(sizeof(long long) == 8);
  1418 JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
  1419 JS_STATIC_ASSERT(sizeof(float) == 4);
  1420 JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
  1421 JS_STATIC_ASSERT(NumericLimits<double>::is_signed);
  1423 // Templated helper to convert FromType to TargetType, for the default case
  1424 // where the trivial POD constructor will do.
  1425 template<class TargetType, class FromType>
  1426 struct ConvertImpl {
  1427   static MOZ_ALWAYS_INLINE TargetType Convert(FromType d) {
  1428     return TargetType(d);
  1430 };
  1432 #ifdef _MSC_VER
  1433 // MSVC can't perform double to unsigned __int64 conversion when the
  1434 // double is greater than 2^63 - 1. Help it along a little.
  1435 template<>
  1436 struct ConvertImpl<uint64_t, double> {
  1437   static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
  1438     return d > 0x7fffffffffffffffui64 ?
  1439            uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
  1440            uint64_t(d);
  1442 };
  1443 #endif
  1445 // C++ doesn't guarantee that exact values are the only ones that will
  1446 // round-trip. In fact, on some platforms, including SPARC, there are pairs of
  1447 // values, a uint64_t and a double, such that neither value is exactly
  1448 // representable in the other type, but they cast to each other.
  1449 #if defined(SPARC) || defined(__powerpc__)
  1450 // Simulate x86 overflow behavior
  1451 template<>
  1452 struct ConvertImpl<uint64_t, double> {
  1453   static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
  1454     return d >= 0xffffffffffffffff ?
  1455            0x8000000000000000 : uint64_t(d);
  1457 };
  1459 template<>
  1460 struct ConvertImpl<int64_t, double> {
  1461   static MOZ_ALWAYS_INLINE int64_t Convert(double d) {
  1462     return d >= 0x7fffffffffffffff ?
  1463            0x8000000000000000 : int64_t(d);
  1465 };
  1466 #endif
  1468 template<class TargetType, class FromType>
  1469 static MOZ_ALWAYS_INLINE TargetType Convert(FromType d)
  1471   return ConvertImpl<TargetType, FromType>::Convert(d);
  1474 template<class TargetType, class FromType>
  1475 static MOZ_ALWAYS_INLINE bool IsAlwaysExact()
  1477   // Return 'true' if TargetType can always exactly represent FromType.
  1478   // This means that:
  1479   // 1) TargetType must be the same or more bits wide as FromType. For integers
  1480   //    represented in 'n' bits, unsigned variants will have 'n' digits while
  1481   //    signed will have 'n - 1'. For floating point types, 'digits' is the
  1482   //    mantissa width.
  1483   // 2) If FromType is signed, TargetType must also be signed. (Floating point
  1484   //    types are always signed.)
  1485   // 3) If TargetType is an exact integral type, FromType must be also.
  1486   if (NumericLimits<TargetType>::digits < NumericLimits<FromType>::digits)
  1487     return false;
  1489   if (NumericLimits<FromType>::is_signed &&
  1490       !NumericLimits<TargetType>::is_signed)
  1491     return false;
  1493   if (!NumericLimits<FromType>::is_exact &&
  1494       NumericLimits<TargetType>::is_exact)
  1495     return false;
  1497   return true;
  1500 // Templated helper to determine if FromType 'i' converts losslessly to
  1501 // TargetType 'j'. Default case where both types are the same signedness.
  1502 template<class TargetType, class FromType, bool TargetSigned, bool FromSigned>
  1503 struct IsExactImpl {
  1504   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1505     JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1506     return FromType(j) == i;
  1508 };
  1510 // Specialization where TargetType is unsigned, FromType is signed.
  1511 template<class TargetType, class FromType>
  1512 struct IsExactImpl<TargetType, FromType, false, true> {
  1513   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1514     JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1515     return i >= 0 && FromType(j) == i;
  1517 };
  1519 // Specialization where TargetType is signed, FromType is unsigned.
  1520 template<class TargetType, class FromType>
  1521 struct IsExactImpl<TargetType, FromType, true, false> {
  1522   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
  1523     JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1524     return TargetType(i) >= 0 && FromType(j) == i;
  1526 };
  1528 // Convert FromType 'i' to TargetType 'result', returning true iff 'result'
  1529 // is an exact representation of 'i'.
  1530 template<class TargetType, class FromType>
  1531 static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
  1533   // Require that TargetType is integral, to simplify conversion.
  1534   JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
  1536   *result = Convert<TargetType>(i);
  1538   // See if we can avoid a dynamic check.
  1539   if (IsAlwaysExact<TargetType, FromType>())
  1540     return true;
  1542   // Return 'true' if 'i' is exactly representable in 'TargetType'.
  1543   return IsExactImpl<TargetType,
  1544                      FromType,
  1545                      NumericLimits<TargetType>::is_signed,
  1546                      NumericLimits<FromType>::is_signed>::Test(i, *result);
  1549 // Templated helper to determine if Type 'i' is negative. Default case
  1550 // where IntegerType is unsigned.
  1551 template<class Type, bool IsSigned>
  1552 struct IsNegativeImpl {
  1553   static MOZ_ALWAYS_INLINE bool Test(Type i) {
  1554     return false;
  1556 };
  1558 // Specialization where Type is signed.
  1559 template<class Type>
  1560 struct IsNegativeImpl<Type, true> {
  1561   static MOZ_ALWAYS_INLINE bool Test(Type i) {
  1562     return i < 0;
  1564 };
  1566 // Determine whether Type 'i' is negative.
  1567 template<class Type>
  1568 static MOZ_ALWAYS_INLINE bool IsNegative(Type i)
  1570   return IsNegativeImpl<Type, NumericLimits<Type>::is_signed>::Test(i);
  1573 // Implicitly convert val to bool, allowing bool, int, and double
  1574 // arguments numerically equal to 0 or 1.
  1575 static bool
  1576 jsvalToBool(JSContext* cx, jsval val, bool* result)
  1578   if (JSVAL_IS_BOOLEAN(val)) {
  1579     *result = JSVAL_TO_BOOLEAN(val);
  1580     return true;
  1582   if (JSVAL_IS_INT(val)) {
  1583     int32_t i = JSVAL_TO_INT(val);
  1584     *result = i != 0;
  1585     return i == 0 || i == 1;
  1587   if (JSVAL_IS_DOUBLE(val)) {
  1588     double d = JSVAL_TO_DOUBLE(val);
  1589     *result = d != 0;
  1590     // Allow -0.
  1591     return d == 1 || d == 0;
  1593   // Don't silently convert null to bool. It's probably a mistake.
  1594   return false;
  1597 // Implicitly convert val to IntegerType, allowing bool, int, double,
  1598 // Int64, UInt64, and CData integer types 't' where all values of 't' are
  1599 // representable by IntegerType.
  1600 template<class IntegerType>
  1601 static bool
  1602 jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
  1604   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1606   if (JSVAL_IS_INT(val)) {
  1607     // Make sure the integer fits in the alotted precision, and has the right
  1608     // sign.
  1609     int32_t i = JSVAL_TO_INT(val);
  1610     return ConvertExact(i, result);
  1612   if (JSVAL_IS_DOUBLE(val)) {
  1613     // Don't silently lose bits here -- check that val really is an
  1614     // integer value, and has the right sign.
  1615     double d = JSVAL_TO_DOUBLE(val);
  1616     return ConvertExact(d, result);
  1618   if (!JSVAL_IS_PRIMITIVE(val)) {
  1619     JSObject* obj = JSVAL_TO_OBJECT(val);
  1620     if (CData::IsCData(obj)) {
  1621       JSObject* typeObj = CData::GetCType(obj);
  1622       void* data = CData::GetData(obj);
  1624       // Check whether the source type is always representable, with exact
  1625       // precision, by the target type. If it is, convert the value.
  1626       switch (CType::GetTypeCode(typeObj)) {
  1627 #define DEFINE_INT_TYPE(name, fromType, ffiType)                               \
  1628       case TYPE_##name:                                                        \
  1629         if (!IsAlwaysExact<IntegerType, fromType>())                           \
  1630           return false;                                                        \
  1631         *result = IntegerType(*static_cast<fromType*>(data));                  \
  1632         return true;
  1633 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1634 #include "ctypes/typedefs.h"
  1635       case TYPE_void_t:
  1636       case TYPE_bool:
  1637       case TYPE_float:
  1638       case TYPE_double:
  1639       case TYPE_float32_t:
  1640       case TYPE_float64_t:
  1641       case TYPE_char:
  1642       case TYPE_signed_char:
  1643       case TYPE_unsigned_char:
  1644       case TYPE_jschar:
  1645       case TYPE_pointer:
  1646       case TYPE_function:
  1647       case TYPE_array:
  1648       case TYPE_struct:
  1649         // Not a compatible number type.
  1650         return false;
  1654     if (Int64::IsInt64(obj)) {
  1655       // Make sure the integer fits in IntegerType.
  1656       int64_t i = Int64Base::GetInt(obj);
  1657       return ConvertExact(i, result);
  1660     if (UInt64::IsUInt64(obj)) {
  1661       // Make sure the integer fits in IntegerType.
  1662       uint64_t i = Int64Base::GetInt(obj);
  1663       return ConvertExact(i, result);
  1666     if (CDataFinalizer::IsCDataFinalizer(obj)) {
  1667       RootedValue innerData(cx);
  1668       if (!CDataFinalizer::GetValue(cx, obj, innerData.address())) {
  1669         return false; // Nothing to convert
  1671       return jsvalToInteger(cx, innerData, result);
  1674     return false;
  1676   if (JSVAL_IS_BOOLEAN(val)) {
  1677     // Implicitly promote boolean values to 0 or 1, like C.
  1678     *result = JSVAL_TO_BOOLEAN(val);
  1679     JS_ASSERT(*result == 0 || *result == 1);
  1680     return true;
  1682   // Don't silently convert null to an integer. It's probably a mistake.
  1683   return false;
  1686 // Implicitly convert val to FloatType, allowing int, double,
  1687 // Int64, UInt64, and CData numeric types 't' where all values of 't' are
  1688 // representable by FloatType.
  1689 template<class FloatType>
  1690 static bool
  1691 jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
  1693   JS_STATIC_ASSERT(!NumericLimits<FloatType>::is_exact);
  1695   // The following casts may silently throw away some bits, but there's
  1696   // no good way around it. Sternly requiring that the 64-bit double
  1697   // argument be exactly representable as a 32-bit float is
  1698   // unrealistic: it would allow 1/2 to pass but not 1/3.
  1699   if (JSVAL_IS_INT(val)) {
  1700     *result = FloatType(JSVAL_TO_INT(val));
  1701     return true;
  1703   if (JSVAL_IS_DOUBLE(val)) {
  1704     *result = FloatType(JSVAL_TO_DOUBLE(val));
  1705     return true;
  1707   if (!JSVAL_IS_PRIMITIVE(val)) {
  1708     JSObject* obj = JSVAL_TO_OBJECT(val);
  1709     if (CData::IsCData(obj)) {
  1710       JSObject* typeObj = CData::GetCType(obj);
  1711       void* data = CData::GetData(obj);
  1713       // Check whether the source type is always representable, with exact
  1714       // precision, by the target type. If it is, convert the value.
  1715       switch (CType::GetTypeCode(typeObj)) {
  1716 #define DEFINE_FLOAT_TYPE(name, fromType, ffiType)                             \
  1717       case TYPE_##name:                                                        \
  1718         if (!IsAlwaysExact<FloatType, fromType>())                             \
  1719           return false;                                                        \
  1720         *result = FloatType(*static_cast<fromType*>(data));                    \
  1721         return true;
  1722 #define DEFINE_INT_TYPE(x, y, z) DEFINE_FLOAT_TYPE(x, y, z)
  1723 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  1724 #include "ctypes/typedefs.h"
  1725       case TYPE_void_t:
  1726       case TYPE_bool:
  1727       case TYPE_char:
  1728       case TYPE_signed_char:
  1729       case TYPE_unsigned_char:
  1730       case TYPE_jschar:
  1731       case TYPE_pointer:
  1732       case TYPE_function:
  1733       case TYPE_array:
  1734       case TYPE_struct:
  1735         // Not a compatible number type.
  1736         return false;
  1740   // Don't silently convert true to 1.0 or false to 0.0, even though C/C++
  1741   // does it. It's likely to be a mistake.
  1742   return false;
  1745 template<class IntegerType>
  1746 static bool
  1747 StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
  1749   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1751   const jschar* cp = string->getChars(nullptr);
  1752   if (!cp)
  1753     return false;
  1755   const jschar* end = cp + string->length();
  1756   if (cp == end)
  1757     return false;
  1759   IntegerType sign = 1;
  1760   if (cp[0] == '-') {
  1761     if (!NumericLimits<IntegerType>::is_signed)
  1762       return false;
  1764     sign = -1;
  1765     ++cp;
  1768   // Assume base-10, unless the string begins with '0x' or '0X'.
  1769   IntegerType base = 10;
  1770   if (end - cp > 2 && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) {
  1771     cp += 2;
  1772     base = 16;
  1775   // Scan the string left to right and build the number,
  1776   // checking for valid characters 0 - 9, a - f, A - F and overflow.
  1777   IntegerType i = 0;
  1778   while (cp != end) {
  1779     jschar c = *cp++;
  1780     if (c >= '0' && c <= '9')
  1781       c -= '0';
  1782     else if (base == 16 && c >= 'a' && c <= 'f')
  1783       c = c - 'a' + 10;
  1784     else if (base == 16 && c >= 'A' && c <= 'F')
  1785       c = c - 'A' + 10;
  1786     else
  1787       return false;
  1789     IntegerType ii = i;
  1790     i = ii * base + sign * c;
  1791     if (i / base != ii) // overflow
  1792       return false;
  1795   *result = i;
  1796   return true;
  1799 // Implicitly convert val to IntegerType, allowing int, double,
  1800 // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
  1801 // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
  1802 template<class IntegerType>
  1803 static bool
  1804 jsvalToBigInteger(JSContext* cx,
  1805                   jsval val,
  1806                   bool allowString,
  1807                   IntegerType* result)
  1809   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1811   if (JSVAL_IS_INT(val)) {
  1812     // Make sure the integer fits in the alotted precision, and has the right
  1813     // sign.
  1814     int32_t i = JSVAL_TO_INT(val);
  1815     return ConvertExact(i, result);
  1817   if (JSVAL_IS_DOUBLE(val)) {
  1818     // Don't silently lose bits here -- check that val really is an
  1819     // integer value, and has the right sign.
  1820     double d = JSVAL_TO_DOUBLE(val);
  1821     return ConvertExact(d, result);
  1823   if (allowString && JSVAL_IS_STRING(val)) {
  1824     // Allow conversion from base-10 or base-16 strings, provided the result
  1825     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
  1826     // to the JS array element operator, which will automatically call
  1827     // toString() on the object for us.)
  1828     return StringToInteger(cx, JSVAL_TO_STRING(val), result);
  1830   if (!JSVAL_IS_PRIMITIVE(val)) {
  1831     // Allow conversion from an Int64 or UInt64 object directly.
  1832     JSObject* obj = JSVAL_TO_OBJECT(val);
  1834     if (UInt64::IsUInt64(obj)) {
  1835       // Make sure the integer fits in IntegerType.
  1836       uint64_t i = Int64Base::GetInt(obj);
  1837       return ConvertExact(i, result);
  1840     if (Int64::IsInt64(obj)) {
  1841       // Make sure the integer fits in IntegerType.
  1842       int64_t i = Int64Base::GetInt(obj);
  1843       return ConvertExact(i, result);
  1846     if (CDataFinalizer::IsCDataFinalizer(obj)) {
  1847       RootedValue innerData(cx);
  1848       if (!CDataFinalizer::GetValue(cx, obj, innerData.address())) {
  1849         return false; // Nothing to convert
  1851       return jsvalToBigInteger(cx, innerData, allowString, result);
  1855   return false;
  1858 // Implicitly convert val to a size value, where the size value is represented
  1859 // by size_t but must also fit in a double.
  1860 static bool
  1861 jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result)
  1863   if (!jsvalToBigInteger(cx, val, allowString, result))
  1864     return false;
  1866   // Also check that the result fits in a double.
  1867   return Convert<size_t>(double(*result)) == *result;
  1870 // Implicitly convert val to IntegerType, allowing int, double,
  1871 // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
  1872 // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
  1873 template<class IntegerType>
  1874 static bool
  1875 jsidToBigInteger(JSContext* cx,
  1876                   jsid val,
  1877                   bool allowString,
  1878                   IntegerType* result)
  1880   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1882   if (JSID_IS_INT(val)) {
  1883     // Make sure the integer fits in the alotted precision, and has the right
  1884     // sign.
  1885     int32_t i = JSID_TO_INT(val);
  1886     return ConvertExact(i, result);
  1888   if (allowString && JSID_IS_STRING(val)) {
  1889     // Allow conversion from base-10 or base-16 strings, provided the result
  1890     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
  1891     // to the JS array element operator, which will automatically call
  1892     // toString() on the object for us.)
  1893     return StringToInteger(cx, JSID_TO_STRING(val), result);
  1895   if (JSID_IS_OBJECT(val)) {
  1896     // Allow conversion from an Int64 or UInt64 object directly.
  1897     JSObject* obj = JSID_TO_OBJECT(val);
  1899     if (UInt64::IsUInt64(obj)) {
  1900       // Make sure the integer fits in IntegerType.
  1901       uint64_t i = Int64Base::GetInt(obj);
  1902       return ConvertExact(i, result);
  1905     if (Int64::IsInt64(obj)) {
  1906       // Make sure the integer fits in IntegerType.
  1907       int64_t i = Int64Base::GetInt(obj);
  1908       return ConvertExact(i, result);
  1911   return false;
  1914 // Implicitly convert val to a size value, where the size value is represented
  1915 // by size_t but must also fit in a double.
  1916 static bool
  1917 jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result)
  1919   if (!jsidToBigInteger(cx, val, allowString, result))
  1920     return false;
  1922   // Also check that the result fits in a double.
  1923   return Convert<size_t>(double(*result)) == *result;
  1926 // Implicitly convert a size value to a jsval, ensuring that the size_t value
  1927 // fits in a double.
  1928 static bool
  1929 SizeTojsval(JSContext* cx, size_t size, jsval* result)
  1931   if (Convert<size_t>(double(size)) != size) {
  1932     JS_ReportError(cx, "size overflow");
  1933     return false;
  1936   *result = JS_NumberValue(double(size));
  1937   return true;
  1940 // Forcefully convert val to IntegerType when explicitly requested.
  1941 template<class IntegerType>
  1942 static bool
  1943 jsvalToIntegerExplicit(jsval val, IntegerType* result)
  1945   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  1947   if (JSVAL_IS_DOUBLE(val)) {
  1948     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
  1949     double d = JSVAL_TO_DOUBLE(val);
  1950     *result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
  1951     return true;
  1953   if (!JSVAL_IS_PRIMITIVE(val)) {
  1954     // Convert Int64 and UInt64 values by C-style cast.
  1955     JSObject* obj = JSVAL_TO_OBJECT(val);
  1956     if (Int64::IsInt64(obj)) {
  1957       int64_t i = Int64Base::GetInt(obj);
  1958       *result = IntegerType(i);
  1959       return true;
  1961     if (UInt64::IsUInt64(obj)) {
  1962       uint64_t i = Int64Base::GetInt(obj);
  1963       *result = IntegerType(i);
  1964       return true;
  1967   return false;
  1970 // Forcefully convert val to a pointer value when explicitly requested.
  1971 static bool
  1972 jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
  1974   if (JSVAL_IS_INT(val)) {
  1975     // int32_t always fits in intptr_t. If the integer is negative, cast through
  1976     // an intptr_t intermediate to sign-extend.
  1977     int32_t i = JSVAL_TO_INT(val);
  1978     *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
  1979     return true;
  1981   if (JSVAL_IS_DOUBLE(val)) {
  1982     double d = JSVAL_TO_DOUBLE(val);
  1983     if (d < 0) {
  1984       // Cast through an intptr_t intermediate to sign-extend.
  1985       intptr_t i = Convert<intptr_t>(d);
  1986       if (double(i) != d)
  1987         return false;
  1989       *result = uintptr_t(i);
  1990       return true;
  1993     // Don't silently lose bits here -- check that val really is an
  1994     // integer value, and has the right sign.
  1995     *result = Convert<uintptr_t>(d);
  1996     return double(*result) == d;
  1998   if (!JSVAL_IS_PRIMITIVE(val)) {
  1999     JSObject* obj = JSVAL_TO_OBJECT(val);
  2000     if (Int64::IsInt64(obj)) {
  2001       int64_t i = Int64Base::GetInt(obj);
  2002       intptr_t p = intptr_t(i);
  2004       // Make sure the integer fits in the alotted precision.
  2005       if (int64_t(p) != i)
  2006         return false;
  2007       *result = uintptr_t(p);
  2008       return true;
  2011     if (UInt64::IsUInt64(obj)) {
  2012       uint64_t i = Int64Base::GetInt(obj);
  2014       // Make sure the integer fits in the alotted precision.
  2015       *result = uintptr_t(i);
  2016       return uint64_t(*result) == i;
  2019   return false;
  2022 template<class IntegerType, class CharType, size_t N, class AP>
  2023 void
  2024 IntegerToString(IntegerType i, int radix, Vector<CharType, N, AP>& result)
  2026   JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
  2028   // The buffer must be big enough for all the bits of IntegerType to fit,
  2029   // in base-2, including '-'.
  2030   CharType buffer[sizeof(IntegerType) * 8 + 1];
  2031   CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
  2032   CharType* cp = end;
  2034   // Build the string in reverse. We use multiplication and subtraction
  2035   // instead of modulus because that's much faster.
  2036   const bool isNegative = IsNegative(i);
  2037   size_t sign = isNegative ? -1 : 1;
  2038   do {
  2039     IntegerType ii = i / IntegerType(radix);
  2040     size_t index = sign * size_t(i - ii * IntegerType(radix));
  2041     *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[index];
  2042     i = ii;
  2043   } while (i != 0);
  2045   if (isNegative)
  2046     *--cp = '-';
  2048   JS_ASSERT(cp >= buffer);
  2049   result.append(cp, end);
  2052 template<class CharType>
  2053 static size_t
  2054 strnlen(const CharType* begin, size_t max)
  2056   for (const CharType* s = begin; s != begin + max; ++s)
  2057     if (*s == 0)
  2058       return s - begin;
  2060   return max;
  2063 // Convert C binary value 'data' of CType 'typeObj' to a JS primitive, where
  2064 // possible; otherwise, construct and return a CData object. The following
  2065 // semantics apply when constructing a CData object for return:
  2066 // * If 'wantPrimitive' is true, the caller indicates that 'result' must be
  2067 //   a JS primitive, and ConvertToJS will fail if 'result' would be a CData
  2068 //   object. Otherwise:
  2069 // * If a CData object 'parentObj' is supplied, the new CData object is
  2070 //   dependent on the given parent and its buffer refers to a slice of the
  2071 //   parent's buffer.
  2072 // * If 'parentObj' is null, the new CData object may or may not own its
  2073 //   resulting buffer depending on the 'ownResult' argument.
  2074 static bool
  2075 ConvertToJS(JSContext* cx,
  2076             HandleObject typeObj,
  2077             HandleObject parentObj,
  2078             void* data,
  2079             bool wantPrimitive,
  2080             bool ownResult,
  2081             jsval* result)
  2083   JS_ASSERT(!parentObj || CData::IsCData(parentObj));
  2084   JS_ASSERT(!parentObj || !ownResult);
  2085   JS_ASSERT(!wantPrimitive || !ownResult);
  2087   TypeCode typeCode = CType::GetTypeCode(typeObj);
  2089   switch (typeCode) {
  2090   case TYPE_void_t:
  2091     *result = JSVAL_VOID;
  2092     break;
  2093   case TYPE_bool:
  2094     *result = *static_cast<bool*>(data) ? JSVAL_TRUE : JSVAL_FALSE;
  2095     break;
  2096 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  2097   case TYPE_##name: {                                                          \
  2098     type value = *static_cast<type*>(data);                                    \
  2099     if (sizeof(type) < 4)                                                      \
  2100       *result = INT_TO_JSVAL(int32_t(value));                                  \
  2101     else                                                                       \
  2102       *result = JS_NumberValue(double(value));                                 \
  2103     break;                                                                     \
  2105 #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
  2106   case TYPE_##name: {                                                          \
  2107     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
  2108     uint64_t value;                                                            \
  2109     RootedObject proto(cx);                                                    \
  2110     if (!NumericLimits<type>::is_signed) {                                     \
  2111       value = *static_cast<type*>(data);                                       \
  2112       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
  2113       proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
  2114       if (!proto)                                                              \
  2115         return false;                                                          \
  2116     } else {                                                                   \
  2117       value = int64_t(*static_cast<type*>(data));                              \
  2118       /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */            \
  2119       proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO);           \
  2120       if (!proto)                                                              \
  2121         return false;                                                          \
  2122     }                                                                          \
  2124     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
  2125       !NumericLimits<type>::is_signed);                                        \
  2126     if (!obj)                                                                  \
  2127       return false;                                                            \
  2128     *result = OBJECT_TO_JSVAL(obj);                                            \
  2129     break;                                                                     \
  2131 #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  2132   case TYPE_##name: {                                                          \
  2133     type value = *static_cast<type*>(data);                                    \
  2134     *result = JS_NumberValue(double(value));                                   \
  2135     break;                                                                     \
  2137 #define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
  2138   case TYPE_##name:                                                            \
  2139     /* Convert to an integer. We have no idea what character encoding to */    \
  2140     /* use, if any. */                                                         \
  2141     *result = INT_TO_JSVAL(*static_cast<type*>(data));                         \
  2142     break;
  2143 #include "ctypes/typedefs.h"
  2144   case TYPE_jschar: {
  2145     // Convert the jschar to a 1-character string.
  2146     JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
  2147     if (!str)
  2148       return false;
  2150     *result = STRING_TO_JSVAL(str);
  2151     break;
  2153   case TYPE_pointer:
  2154   case TYPE_array:
  2155   case TYPE_struct: {
  2156     // We're about to create a new CData object to return. If the caller doesn't
  2157     // want this, return early.
  2158     if (wantPrimitive) {
  2159       JS_ReportError(cx, "cannot convert to primitive value");
  2160       return false;
  2163     JSObject* obj = CData::Create(cx, typeObj, parentObj, data, ownResult);
  2164     if (!obj)
  2165       return false;
  2167     *result = OBJECT_TO_JSVAL(obj);
  2168     break;
  2170   case TYPE_function:
  2171     MOZ_ASSUME_UNREACHABLE("cannot return a FunctionType");
  2174   return true;
  2177 // Determine if the contents of a typed array can be converted without
  2178 // ambiguity to a C type. Elements of a Int8Array are converted to
  2179 // ctypes.int8_t, UInt8Array to ctypes.uint8_t, etc.
  2180 bool CanConvertTypedArrayItemTo(JSObject *baseType, JSObject *valObj, JSContext *cx) {
  2181   TypeCode baseTypeCode = CType::GetTypeCode(baseType);
  2182   if (baseTypeCode == TYPE_void_t) {
  2183     return true;
  2185   TypeCode elementTypeCode;
  2186   switch (JS_GetArrayBufferViewType(valObj)) {
  2187   case ScalarTypeDescr::TYPE_INT8:
  2188     elementTypeCode = TYPE_int8_t;
  2189     break;
  2190   case ScalarTypeDescr::TYPE_UINT8:
  2191   case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
  2192     elementTypeCode = TYPE_uint8_t;
  2193     break;
  2194   case ScalarTypeDescr::TYPE_INT16:
  2195     elementTypeCode = TYPE_int16_t;
  2196     break;
  2197   case ScalarTypeDescr::TYPE_UINT16:
  2198     elementTypeCode = TYPE_uint16_t;
  2199     break;
  2200   case ScalarTypeDescr::TYPE_INT32:
  2201     elementTypeCode = TYPE_int32_t;
  2202     break;
  2203   case ScalarTypeDescr::TYPE_UINT32:
  2204     elementTypeCode = TYPE_uint32_t;
  2205     break;
  2206   case ScalarTypeDescr::TYPE_FLOAT32:
  2207     elementTypeCode = TYPE_float32_t;
  2208     break;
  2209   case ScalarTypeDescr::TYPE_FLOAT64:
  2210     elementTypeCode = TYPE_float64_t;
  2211     break;
  2212   default:
  2213     return false;
  2215   return elementTypeCode == baseTypeCode;
  2218 // Implicitly convert jsval 'val' to a C binary representation of CType
  2219 // 'targetType', storing the result in 'buffer'. Adequate space must be
  2220 // provided in 'buffer' by the caller. This function generally does minimal
  2221 // coercion between types. There are two cases in which this function is used:
  2222 // 1) The target buffer is internal to a CData object; we simply write data
  2223 //    into it.
  2224 // 2) We are converting an argument for an ffi call, in which case 'isArgument'
  2225 //    will be true. This allows us to handle a special case: if necessary,
  2226 //    we can autoconvert a JS string primitive to a pointer-to-character type.
  2227 //    In this case, ownership of the allocated string is handed off to the
  2228 //    caller; 'freePointer' will be set to indicate this.
  2229 static bool
  2230 ImplicitConvert(JSContext* cx,
  2231                 HandleValue val,
  2232                 JSObject* targetType_,
  2233                 void* buffer,
  2234                 bool isArgument,
  2235                 bool* freePointer)
  2237   RootedObject targetType(cx, targetType_);
  2238   JS_ASSERT(CType::IsSizeDefined(targetType));
  2240   // First, check if val is either a CData object or a CDataFinalizer
  2241   // of type targetType.
  2242   JSObject* sourceData = nullptr;
  2243   JSObject* sourceType = nullptr;
  2244   RootedObject valObj(cx, nullptr);
  2245   if (!JSVAL_IS_PRIMITIVE(val)) {
  2246     valObj = JSVAL_TO_OBJECT(val);
  2247     if (CData::IsCData(valObj)) {
  2248       sourceData = valObj;
  2249       sourceType = CData::GetCType(sourceData);
  2251       // If the types are equal, copy the buffer contained within the CData.
  2252       // (Note that the buffers may overlap partially or completely.)
  2253       if (CType::TypesEqual(sourceType, targetType)) {
  2254         size_t size = CType::GetSize(sourceType);
  2255         memmove(buffer, CData::GetData(sourceData), size);
  2256         return true;
  2258     } else if (CDataFinalizer::IsCDataFinalizer(valObj)) {
  2259       sourceData = valObj;
  2260       sourceType = CDataFinalizer::GetCType(cx, sourceData);
  2262       CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  2263         JS_GetPrivate(sourceData);
  2265       if (!p) {
  2266         // We have called |dispose| or |forget| already.
  2267         JS_ReportError(cx, "Attempting to convert an empty CDataFinalizer");
  2268         return false;
  2271       // If the types are equal, copy the buffer contained within the CData.
  2272       if (CType::TypesEqual(sourceType, targetType)) {
  2273         memmove(buffer, p->cargs, p->cargs_size);
  2274         return true;
  2279   TypeCode targetCode = CType::GetTypeCode(targetType);
  2281   switch (targetCode) {
  2282   case TYPE_bool: {
  2283     // Do not implicitly lose bits, but allow the values 0, 1, and -0.
  2284     // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
  2285     bool result;
  2286     if (!jsvalToBool(cx, val, &result))
  2287       return TypeError(cx, "boolean", val);
  2288     *static_cast<bool*>(buffer) = result;
  2289     break;
  2291 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  2292   case TYPE_##name: {                                                          \
  2293     /* Do not implicitly lose bits. */                                         \
  2294     type result;                                                               \
  2295     if (!jsvalToInteger(cx, val, &result))                                     \
  2296       return TypeError(cx, #name, val);                                        \
  2297     *static_cast<type*>(buffer) = result;                                      \
  2298     break;                                                                     \
  2300 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  2301 #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  2302   case TYPE_##name: {                                                          \
  2303     type result;                                                               \
  2304     if (!jsvalToFloat(cx, val, &result))                                       \
  2305       return TypeError(cx, #name, val);                                        \
  2306     *static_cast<type*>(buffer) = result;                                      \
  2307     break;                                                                     \
  2309 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  2310 #define DEFINE_JSCHAR_TYPE(name, type, ffiType)                                \
  2311   case TYPE_##name: {                                                          \
  2312     /* Convert from a 1-character string, regardless of encoding, */           \
  2313     /* or from an integer, provided the result fits in 'type'. */              \
  2314     type result;                                                               \
  2315     if (JSVAL_IS_STRING(val)) {                                                \
  2316       JSString* str = JSVAL_TO_STRING(val);                                    \
  2317       if (str->length() != 1)                                                  \
  2318         return TypeError(cx, #name, val);                                      \
  2319       const jschar *chars = str->getChars(cx);                                 \
  2320       if (!chars)                                                              \
  2321         return false;                                                          \
  2322       result = chars[0];                                                       \
  2323     } else if (!jsvalToInteger(cx, val, &result)) {                            \
  2324       return TypeError(cx, #name, val);                                        \
  2325     }                                                                          \
  2326     *static_cast<type*>(buffer) = result;                                      \
  2327     break;                                                                     \
  2329 #include "ctypes/typedefs.h"
  2330   case TYPE_pointer: {
  2331     if (JSVAL_IS_NULL(val)) {
  2332       // Convert to a null pointer.
  2333       *static_cast<void**>(buffer) = nullptr;
  2334       break;
  2337     JS::Rooted<JSObject*> baseType(cx, PointerType::GetBaseType(targetType));
  2338     if (sourceData) {
  2339       // First, determine if the targetType is ctypes.void_t.ptr.
  2340       TypeCode sourceCode = CType::GetTypeCode(sourceType);
  2341       void* sourceBuffer = CData::GetData(sourceData);
  2342       bool voidptrTarget = CType::GetTypeCode(baseType) == TYPE_void_t;
  2344       if (sourceCode == TYPE_pointer && voidptrTarget) {
  2345         // Autoconvert if targetType is ctypes.voidptr_t.
  2346         *static_cast<void**>(buffer) = *static_cast<void**>(sourceBuffer);
  2347         break;
  2349       if (sourceCode == TYPE_array) {
  2350         // Autoconvert an array to a ctypes.void_t.ptr or to
  2351         // sourceType.elementType.ptr, just like C.
  2352         JSObject* elementType = ArrayType::GetBaseType(sourceType);
  2353         if (voidptrTarget || CType::TypesEqual(baseType, elementType)) {
  2354           *static_cast<void**>(buffer) = sourceBuffer;
  2355           break;
  2359     } else if (isArgument && JSVAL_IS_STRING(val)) {
  2360       // Convert the string for the ffi call. This requires allocating space
  2361       // which the caller assumes ownership of.
  2362       // TODO: Extend this so we can safely convert strings at other times also.
  2363       JSString* sourceString = JSVAL_TO_STRING(val);
  2364       size_t sourceLength = sourceString->length();
  2365       const jschar* sourceChars = sourceString->getChars(cx);
  2366       if (!sourceChars)
  2367         return false;
  2369       switch (CType::GetTypeCode(baseType)) {
  2370       case TYPE_char:
  2371       case TYPE_signed_char:
  2372       case TYPE_unsigned_char: {
  2373         // Convert from UTF-16 to UTF-8.
  2374         size_t nbytes =
  2375           GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  2376         if (nbytes == (size_t) -1)
  2377           return false;
  2379         char** charBuffer = static_cast<char**>(buffer);
  2380         *charBuffer = cx->pod_malloc<char>(nbytes + 1);
  2381         if (!*charBuffer) {
  2382           JS_ReportAllocationOverflow(cx);
  2383           return false;
  2386         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
  2387                     *charBuffer, &nbytes));
  2388         (*charBuffer)[nbytes] = 0;
  2389         *freePointer = true;
  2390         break;
  2392       case TYPE_jschar: {
  2393         // Copy the jschar string data. (We could provide direct access to the
  2394         // JSString's buffer, but this approach is safer if the caller happens
  2395         // to modify the string.)
  2396         jschar** jscharBuffer = static_cast<jschar**>(buffer);
  2397         *jscharBuffer = cx->pod_malloc<jschar>(sourceLength + 1);
  2398         if (!*jscharBuffer) {
  2399           JS_ReportAllocationOverflow(cx);
  2400           return false;
  2403         *freePointer = true;
  2404         memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
  2405         (*jscharBuffer)[sourceLength] = 0;
  2406         break;
  2408       default:
  2409         return TypeError(cx, "string pointer", val);
  2411       break;
  2412     } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayBufferObject(valObj)) {
  2413       // Convert ArrayBuffer to pointer without any copy.
  2414       // Just as with C arrays, we make no effort to
  2415       // keep the ArrayBuffer alive.
  2416       void* p = JS_GetStableArrayBufferData(cx, valObj);
  2417       if (!p)
  2418           return false;
  2419       *static_cast<void**>(buffer) = p;
  2420       break;
  2421     } if (!JSVAL_IS_PRIMITIVE(val) && JS_IsTypedArrayObject(valObj)) {
  2422       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
  2423         return TypeError(cx, "typed array with the appropriate type", val);
  2426       // Convert TypedArray to pointer without any copy.
  2427       // Just as with C arrays, we make no effort to
  2428       // keep the TypedArray alive.
  2429       *static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
  2430       break;
  2432     return TypeError(cx, "pointer", val);
  2434   case TYPE_array: {
  2435     RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
  2436     size_t targetLength = ArrayType::GetLength(targetType);
  2438     if (JSVAL_IS_STRING(val)) {
  2439       JSString* sourceString = JSVAL_TO_STRING(val);
  2440       size_t sourceLength = sourceString->length();
  2441       const jschar* sourceChars = sourceString->getChars(cx);
  2442       if (!sourceChars)
  2443         return false;
  2445       switch (CType::GetTypeCode(baseType)) {
  2446       case TYPE_char:
  2447       case TYPE_signed_char:
  2448       case TYPE_unsigned_char: {
  2449         // Convert from UTF-16 to UTF-8.
  2450         size_t nbytes =
  2451           GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  2452         if (nbytes == (size_t) -1)
  2453           return false;
  2455         if (targetLength < nbytes) {
  2456           JS_ReportError(cx, "ArrayType has insufficient length");
  2457           return false;
  2460         char* charBuffer = static_cast<char*>(buffer);
  2461         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
  2462                     charBuffer, &nbytes));
  2464         if (targetLength > nbytes)
  2465           charBuffer[nbytes] = 0;
  2467         break;
  2469       case TYPE_jschar: {
  2470         // Copy the string data, jschar for jschar, including the terminator
  2471         // if there's space.
  2472         if (targetLength < sourceLength) {
  2473           JS_ReportError(cx, "ArrayType has insufficient length");
  2474           return false;
  2477         memcpy(buffer, sourceChars, sourceLength * sizeof(jschar));
  2478         if (targetLength > sourceLength)
  2479           static_cast<jschar*>(buffer)[sourceLength] = 0;
  2481         break;
  2483       default:
  2484         return TypeError(cx, "array", val);
  2487     } else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayObject(cx, valObj)) {
  2488       // Convert each element of the array by calling ImplicitConvert.
  2489       uint32_t sourceLength;
  2490       if (!JS_GetArrayLength(cx, valObj, &sourceLength) ||
  2491           targetLength != size_t(sourceLength)) {
  2492         JS_ReportError(cx, "ArrayType length does not match source array length");
  2493         return false;
  2496       // Convert into an intermediate, in case of failure.
  2497       size_t elementSize = CType::GetSize(baseType);
  2498       size_t arraySize = elementSize * targetLength;
  2499       AutoPtr<char> intermediate(cx->pod_malloc<char>(arraySize));
  2500       if (!intermediate) {
  2501         JS_ReportAllocationOverflow(cx);
  2502         return false;
  2505       for (uint32_t i = 0; i < sourceLength; ++i) {
  2506         RootedValue item(cx);
  2507         if (!JS_GetElement(cx, valObj, i, &item))
  2508           return false;
  2510         char* data = intermediate.get() + elementSize * i;
  2511         if (!ImplicitConvert(cx, item, baseType, data, false, nullptr))
  2512           return false;
  2515       memcpy(buffer, intermediate.get(), arraySize);
  2517     } else if (!JSVAL_IS_PRIMITIVE(val) &&
  2518                JS_IsArrayBufferObject(valObj)) {
  2519       // Check that array is consistent with type, then
  2520       // copy the array.
  2521       uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
  2522       size_t elementSize = CType::GetSize(baseType);
  2523       size_t arraySize = elementSize * targetLength;
  2524       if (arraySize != size_t(sourceLength)) {
  2525         JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
  2526         return false;
  2528       memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
  2529       break;
  2530     }  else if (!JSVAL_IS_PRIMITIVE(val) &&
  2531                JS_IsTypedArrayObject(valObj)) {
  2532       // Check that array is consistent with type, then
  2533       // copy the array.
  2534       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
  2535         return TypeError(cx, "typed array with the appropriate type", val);
  2538       uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
  2539       size_t elementSize = CType::GetSize(baseType);
  2540       size_t arraySize = elementSize * targetLength;
  2541       if (arraySize != size_t(sourceLength)) {
  2542         JS_ReportError(cx, "typed array length does not match source TypedArray length");
  2543         return false;
  2545       memcpy(buffer, JS_GetArrayBufferViewData(valObj), sourceLength);
  2546       break;
  2547     } else {
  2548       // Don't implicitly convert to string. Users can implicitly convert
  2549       // with `String(x)` or `""+x`.
  2550       return TypeError(cx, "array", val);
  2552     break;
  2554   case TYPE_struct: {
  2555     if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) {
  2556       // Enumerate the properties of the object; if they match the struct
  2557       // specification, convert the fields.
  2558       RootedObject iter(cx, JS_NewPropertyIterator(cx, valObj));
  2559       if (!iter)
  2560         return false;
  2562       // Convert into an intermediate, in case of failure.
  2563       size_t structSize = CType::GetSize(targetType);
  2564       AutoPtr<char> intermediate(cx->pod_malloc<char>(structSize));
  2565       if (!intermediate) {
  2566         JS_ReportAllocationOverflow(cx);
  2567         return false;
  2570       RootedId id(cx);
  2571       size_t i = 0;
  2572       while (1) {
  2573         if (!JS_NextProperty(cx, iter, id.address()))
  2574           return false;
  2575         if (JSID_IS_VOID(id))
  2576           break;
  2578         if (!JSID_IS_STRING(id)) {
  2579           JS_ReportError(cx, "property name is not a string");
  2580           return false;
  2583         JSFlatString *name = JSID_TO_FLAT_STRING(id);
  2584         const FieldInfo* field = StructType::LookupField(cx, targetType, name);
  2585         if (!field)
  2586           return false;
  2588         RootedValue prop(cx);
  2589         if (!JS_GetPropertyById(cx, valObj, id, &prop))
  2590           return false;
  2592         // Convert the field via ImplicitConvert().
  2593         char* fieldData = intermediate.get() + field->mOffset;
  2594         if (!ImplicitConvert(cx, prop, field->mType, fieldData, false, nullptr))
  2595           return false;
  2597         ++i;
  2600       const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
  2601       if (i != fields->count()) {
  2602         JS_ReportError(cx, "missing fields");
  2603         return false;
  2606       memcpy(buffer, intermediate.get(), structSize);
  2607       break;
  2610     return TypeError(cx, "struct", val);
  2612   case TYPE_void_t:
  2613   case TYPE_function:
  2614     MOZ_ASSUME_UNREACHABLE("invalid type");
  2617   return true;
  2620 // Convert jsval 'val' to a C binary representation of CType 'targetType',
  2621 // storing the result in 'buffer'. This function is more forceful than
  2622 // ImplicitConvert.
  2623 static bool
  2624 ExplicitConvert(JSContext* cx, HandleValue val, HandleObject targetType, void* buffer)
  2626   // If ImplicitConvert succeeds, use that result.
  2627   if (ImplicitConvert(cx, val, targetType, buffer, false, nullptr))
  2628     return true;
  2630   // If ImplicitConvert failed, and there is no pending exception, then assume
  2631   // hard failure (out of memory, or some other similarly serious condition).
  2632   // We store any pending exception in case we need to re-throw it.
  2633   RootedValue ex(cx);
  2634   if (!JS_GetPendingException(cx, &ex))
  2635     return false;
  2637   // Otherwise, assume soft failure. Clear the pending exception so that we
  2638   // can throw a different one as required.
  2639   JS_ClearPendingException(cx);
  2641   TypeCode type = CType::GetTypeCode(targetType);
  2643   switch (type) {
  2644   case TYPE_bool: {
  2645     *static_cast<bool*>(buffer) = ToBoolean(val);
  2646     break;
  2648 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  2649   case TYPE_##name: {                                                          \
  2650     /* Convert numeric values with a C-style cast, and */                      \
  2651     /* allow conversion from a base-10 or base-16 string. */                   \
  2652     type result;                                                               \
  2653     if (!jsvalToIntegerExplicit(val, &result) &&                               \
  2654         (!JSVAL_IS_STRING(val) ||                                              \
  2655          !StringToInteger(cx, JSVAL_TO_STRING(val), &result)))                 \
  2656       return TypeError(cx, #name, val);                                        \
  2657     *static_cast<type*>(buffer) = result;                                      \
  2658     break;                                                                     \
  2660 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  2661 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  2662 #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z)
  2663 #include "ctypes/typedefs.h"
  2664   case TYPE_pointer: {
  2665     // Convert a number, Int64 object, or UInt64 object to a pointer.
  2666     uintptr_t result;
  2667     if (!jsvalToPtrExplicit(cx, val, &result))
  2668       return TypeError(cx, "pointer", val);
  2669     *static_cast<uintptr_t*>(buffer) = result;
  2670     break;
  2672   case TYPE_float32_t:
  2673   case TYPE_float64_t:
  2674   case TYPE_float:
  2675   case TYPE_double:
  2676   case TYPE_array:
  2677   case TYPE_struct:
  2678     // ImplicitConvert is sufficient. Re-throw the exception it generated.
  2679     JS_SetPendingException(cx, ex);
  2680     return false;
  2681   case TYPE_void_t:
  2682   case TYPE_function:
  2683     MOZ_ASSUME_UNREACHABLE("invalid type");
  2685   return true;
  2688 // Given a CType 'typeObj', generate a string describing the C type declaration
  2689 // corresponding to 'typeObj'. For instance, the CType constructed from
  2690 // 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string
  2691 // 'int32_t*(**)[4]'.
  2692 static JSString*
  2693 BuildTypeName(JSContext* cx, JSObject* typeObj_)
  2695   AutoString result;
  2696   RootedObject typeObj(cx, typeObj_);
  2698   // Walk the hierarchy of types, outermost to innermost, building up the type
  2699   // string. This consists of the base type, which goes on the left.
  2700   // Derived type modifiers (* and []) build from the inside outward, with
  2701   // pointers on the left and arrays on the right. An excellent description
  2702   // of the rules for building C type declarations can be found at:
  2703   // http://unixwiz.net/techtips/reading-cdecl.html
  2704   TypeCode prevGrouping = CType::GetTypeCode(typeObj), currentGrouping;
  2705   while (1) {
  2706     currentGrouping = CType::GetTypeCode(typeObj);
  2707     switch (currentGrouping) {
  2708     case TYPE_pointer: {
  2709       // Pointer types go on the left.
  2710       PrependString(result, "*");
  2712       typeObj = PointerType::GetBaseType(typeObj);
  2713       prevGrouping = currentGrouping;
  2714       continue;
  2716     case TYPE_array: {
  2717       if (prevGrouping == TYPE_pointer) {
  2718         // Outer type is pointer, inner type is array. Grouping is required.
  2719         PrependString(result, "(");
  2720         AppendString(result, ")");
  2723       // Array types go on the right.
  2724       AppendString(result, "[");
  2725       size_t length;
  2726       if (ArrayType::GetSafeLength(typeObj, &length))
  2727         IntegerToString(length, 10, result);
  2729       AppendString(result, "]");
  2731       typeObj = ArrayType::GetBaseType(typeObj);
  2732       prevGrouping = currentGrouping;
  2733       continue;
  2735     case TYPE_function: {
  2736       FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  2738       // Add in the calling convention, if it's not cdecl.
  2739       // There's no trailing or leading space needed here, as none of the
  2740       // modifiers can produce a string beginning with an identifier ---
  2741       // except for TYPE_function itself, which is fine because functions
  2742       // can't return functions.
  2743       ABICode abi = GetABICode(fninfo->mABI);
  2744       if (abi == ABI_STDCALL)
  2745         PrependString(result, "__stdcall");
  2746       else if (abi == ABI_WINAPI)
  2747         PrependString(result, "WINAPI");
  2749       // Function application binds more tightly than dereferencing, so
  2750       // wrap pointer types in parens. Functions can't return functions
  2751       // (only pointers to them), and arrays can't hold functions
  2752       // (similarly), so we don't need to address those cases.
  2753       if (prevGrouping == TYPE_pointer) {
  2754         PrependString(result, "(");
  2755         AppendString(result, ")");
  2758       // Argument list goes on the right.
  2759       AppendString(result, "(");
  2760       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  2761         RootedObject argType(cx, fninfo->mArgTypes[i]);
  2762         JSString* argName = CType::GetName(cx, argType);
  2763         AppendString(result, argName);
  2764         if (i != fninfo->mArgTypes.length() - 1 ||
  2765             fninfo->mIsVariadic)
  2766           AppendString(result, ", ");
  2768       if (fninfo->mIsVariadic)
  2769         AppendString(result, "...");
  2770       AppendString(result, ")");
  2772       // Set 'typeObj' to the return type, and let the loop process it.
  2773       // 'prevGrouping' doesn't matter here, because functions cannot return
  2774       // arrays -- thus the parenthetical rules don't get tickled.
  2775       typeObj = fninfo->mReturnType;
  2776       continue;
  2778     default:
  2779       // Either a basic or struct type. Use the type's name as the base type.
  2780       break;
  2782     break;
  2785   // If prepending the base type name directly would splice two
  2786   // identifiers, insert a space.
  2787   if (('a' <= result[0] && result[0] <= 'z') ||
  2788       ('A' <= result[0] && result[0] <= 'Z') ||
  2789       (result[0] == '_'))
  2790     PrependString(result, " ");
  2792   // Stick the base type and derived type parts together.
  2793   JSString* baseName = CType::GetName(cx, typeObj);
  2794   PrependString(result, baseName);
  2795   return NewUCString(cx, result);
  2798 // Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
  2799 // would construct the same CType. If 'makeShort' is true, assume that any
  2800 // StructType 't' is bound to an in-scope variable of name 't.name', and use
  2801 // that variable in place of generating a string to construct the type 't'.
  2802 // (This means the type comparison function CType::TypesEqual will return true
  2803 // when comparing the input and output of BuildTypeSource, since struct
  2804 // equality is determined by strict JSObject pointer equality.)
  2805 static void
  2806 BuildTypeSource(JSContext* cx,
  2807                 JSObject* typeObj_,
  2808                 bool makeShort,
  2809                 AutoString& result)
  2811   RootedObject typeObj(cx, typeObj_);
  2813   // Walk the types, building up the toSource() string.
  2814   switch (CType::GetTypeCode(typeObj)) {
  2815   case TYPE_void_t:
  2816 #define DEFINE_TYPE(name, type, ffiType)  \
  2817   case TYPE_##name:
  2818 #include "ctypes/typedefs.h"
  2820     AppendString(result, "ctypes.");
  2821     JSString* nameStr = CType::GetName(cx, typeObj);
  2822     AppendString(result, nameStr);
  2823     break;
  2825   case TYPE_pointer: {
  2826     RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
  2828     // Specialcase ctypes.voidptr_t.
  2829     if (CType::GetTypeCode(baseType) == TYPE_void_t) {
  2830       AppendString(result, "ctypes.voidptr_t");
  2831       break;
  2834     // Recursively build the source string, and append '.ptr'.
  2835     BuildTypeSource(cx, baseType, makeShort, result);
  2836     AppendString(result, ".ptr");
  2837     break;
  2839   case TYPE_function: {
  2840     FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  2842     AppendString(result, "ctypes.FunctionType(");
  2844     switch (GetABICode(fninfo->mABI)) {
  2845     case ABI_DEFAULT:
  2846       AppendString(result, "ctypes.default_abi, ");
  2847       break;
  2848     case ABI_STDCALL:
  2849       AppendString(result, "ctypes.stdcall_abi, ");
  2850       break;
  2851     case ABI_WINAPI:
  2852       AppendString(result, "ctypes.winapi_abi, ");
  2853       break;
  2854     case INVALID_ABI:
  2855       MOZ_ASSUME_UNREACHABLE("invalid abi");
  2858     // Recursively build the source string describing the function return and
  2859     // argument types.
  2860     BuildTypeSource(cx, fninfo->mReturnType, true, result);
  2862     if (fninfo->mArgTypes.length() > 0) {
  2863       AppendString(result, ", [");
  2864       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  2865         BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
  2866         if (i != fninfo->mArgTypes.length() - 1 ||
  2867             fninfo->mIsVariadic)
  2868           AppendString(result, ", ");
  2870       if (fninfo->mIsVariadic)
  2871         AppendString(result, "\"...\"");
  2872       AppendString(result, "]");
  2875     AppendString(result, ")");
  2876     break;
  2878   case TYPE_array: {
  2879     // Recursively build the source string, and append '.array(n)',
  2880     // where n is the array length, or the empty string if the array length
  2881     // is undefined.
  2882     JSObject* baseType = ArrayType::GetBaseType(typeObj);
  2883     BuildTypeSource(cx, baseType, makeShort, result);
  2884     AppendString(result, ".array(");
  2886     size_t length;
  2887     if (ArrayType::GetSafeLength(typeObj, &length))
  2888       IntegerToString(length, 10, result);
  2890     AppendString(result, ")");
  2891     break;
  2893   case TYPE_struct: {
  2894     JSString* name = CType::GetName(cx, typeObj);
  2896     if (makeShort) {
  2897       // Shorten the type declaration by assuming that StructType 't' is bound
  2898       // to an in-scope variable of name 't.name'.
  2899       AppendString(result, name);
  2900       break;
  2903     // Write the full struct declaration.
  2904     AppendString(result, "ctypes.StructType(\"");
  2905     AppendString(result, name);
  2906     AppendString(result, "\"");
  2908     // If it's an opaque struct, we're done.
  2909     if (!CType::IsSizeDefined(typeObj)) {
  2910       AppendString(result, ")");
  2911       break;
  2914     AppendString(result, ", [");
  2916     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
  2917     size_t length = fields->count();
  2918     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
  2919     if (!fieldsArray.resize(length))
  2920       break;
  2922     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
  2923       fieldsArray[r.front().value().mIndex] = &r.front();
  2925     for (size_t i = 0; i < length; ++i) {
  2926       const FieldInfoHash::Entry* entry = fieldsArray[i];
  2927       AppendString(result, "{ \"");
  2928       AppendString(result, entry->key());
  2929       AppendString(result, "\": ");
  2930       BuildTypeSource(cx, entry->value().mType, true, result);
  2931       AppendString(result, " }");
  2932       if (i != length - 1)
  2933         AppendString(result, ", ");
  2936     AppendString(result, "])");
  2937     break;
  2942 // Given a CData object of CType 'typeObj' with binary value 'data', generate a
  2943 // string 'result' such that 'eval(result)' would construct a CData object with
  2944 // the same CType and containing the same binary value. This assumes that any
  2945 // StructType 't' is bound to an in-scope variable of name 't.name'. (This means
  2946 // the type comparison function CType::TypesEqual will return true when
  2947 // comparing the types, since struct equality is determined by strict JSObject
  2948 // pointer equality.) Further, if 'isImplicit' is true, ensure that the
  2949 // resulting string can ImplicitConvert successfully if passed to another data
  2950 // constructor. (This is important when called recursively, since fields of
  2951 // structs and arrays are converted with ImplicitConvert.)
  2952 static bool
  2953 BuildDataSource(JSContext* cx,
  2954                 HandleObject typeObj,
  2955                 void* data,
  2956                 bool isImplicit,
  2957                 AutoString& result)
  2959   TypeCode type = CType::GetTypeCode(typeObj);
  2960   switch (type) {
  2961   case TYPE_bool:
  2962     if (*static_cast<bool*>(data))
  2963       AppendString(result, "true");
  2964     else
  2965       AppendString(result, "false");
  2966     break;
  2967 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  2968   case TYPE_##name:                                                            \
  2969     /* Serialize as a primitive decimal integer. */                            \
  2970     IntegerToString(*static_cast<type*>(data), 10, result);                    \
  2971     break;
  2972 #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
  2973   case TYPE_##name:                                                            \
  2974     /* Serialize as a wrapped decimal integer. */                              \
  2975     if (!NumericLimits<type>::is_signed)                                       \
  2976       AppendString(result, "ctypes.UInt64(\"");                                \
  2977     else                                                                       \
  2978       AppendString(result, "ctypes.Int64(\"");                                 \
  2980     IntegerToString(*static_cast<type*>(data), 10, result);                    \
  2981     AppendString(result, "\")");                                               \
  2982     break;
  2983 #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
  2984   case TYPE_##name: {                                                          \
  2985     /* Serialize as a primitive double. */                                     \
  2986     double fp = *static_cast<type*>(data);                                     \
  2987     ToCStringBuf cbuf;                                                         \
  2988     char* str = NumberToCString(cx, &cbuf, fp);                                \
  2989     if (!str) {                                                                \
  2990       JS_ReportOutOfMemory(cx);                                                \
  2991       return false;                                                            \
  2992     }                                                                          \
  2994     result.append(str, strlen(str));                                           \
  2995     break;                                                                     \
  2997 #define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
  2998   case TYPE_##name:                                                            \
  2999     /* Serialize as an integer. */                                             \
  3000     IntegerToString(*static_cast<type*>(data), 10, result);                    \
  3001     break;
  3002 #include "ctypes/typedefs.h"
  3003   case TYPE_jschar: {
  3004     // Serialize as a 1-character JS string.
  3005     JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
  3006     if (!str)
  3007       return false;
  3009     // Escape characters, and quote as necessary.
  3010     RootedValue valStr(cx, StringValue(str));
  3011     JSString* src = JS_ValueToSource(cx, valStr);
  3012     if (!src)
  3013       return false;
  3015     AppendString(result, src);
  3016     break;
  3018   case TYPE_pointer:
  3019   case TYPE_function: {
  3020     if (isImplicit) {
  3021       // The result must be able to ImplicitConvert successfully.
  3022       // Wrap in a type constructor, then serialize for ExplicitConvert.
  3023       BuildTypeSource(cx, typeObj, true, result);
  3024       AppendString(result, "(");
  3027     // Serialize the pointer value as a wrapped hexadecimal integer.
  3028     uintptr_t ptr = *static_cast<uintptr_t*>(data);
  3029     AppendString(result, "ctypes.UInt64(\"0x");
  3030     IntegerToString(ptr, 16, result);
  3031     AppendString(result, "\")");
  3033     if (isImplicit)
  3034       AppendString(result, ")");
  3036     break;
  3038   case TYPE_array: {
  3039     // Serialize each element of the array recursively. Each element must
  3040     // be able to ImplicitConvert successfully.
  3041     RootedObject baseType(cx, ArrayType::GetBaseType(typeObj));
  3042     AppendString(result, "[");
  3044     size_t length = ArrayType::GetLength(typeObj);
  3045     size_t elementSize = CType::GetSize(baseType);
  3046     for (size_t i = 0; i < length; ++i) {
  3047       char* element = static_cast<char*>(data) + elementSize * i;
  3048       if (!BuildDataSource(cx, baseType, element, true, result))
  3049         return false;
  3051       if (i + 1 < length)
  3052         AppendString(result, ", ");
  3054     AppendString(result, "]");
  3055     break;
  3057   case TYPE_struct: {
  3058     if (isImplicit) {
  3059       // The result must be able to ImplicitConvert successfully.
  3060       // Serialize the data as an object with properties, rather than
  3061       // a sequence of arguments to the StructType constructor.
  3062       AppendString(result, "{");
  3065     // Serialize each field of the struct recursively. Each field must
  3066     // be able to ImplicitConvert successfully.
  3067     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
  3068     size_t length = fields->count();
  3069     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
  3070     if (!fieldsArray.resize(length))
  3071       return false;
  3073     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
  3074       fieldsArray[r.front().value().mIndex] = &r.front();
  3076     for (size_t i = 0; i < length; ++i) {
  3077       const FieldInfoHash::Entry* entry = fieldsArray[i];
  3079       if (isImplicit) {
  3080         AppendString(result, "\"");
  3081         AppendString(result, entry->key());
  3082         AppendString(result, "\": ");
  3085       char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
  3086       RootedObject entryType(cx, entry->value().mType);
  3087       if (!BuildDataSource(cx, entryType, fieldData, true, result))
  3088         return false;
  3090       if (i + 1 != length)
  3091         AppendString(result, ", ");
  3094     if (isImplicit)
  3095       AppendString(result, "}");
  3097     break;
  3099   case TYPE_void_t:
  3100     MOZ_ASSUME_UNREACHABLE("invalid type");
  3103   return true;
  3106 /*******************************************************************************
  3107 ** JSAPI callback function implementations
  3108 *******************************************************************************/
  3110 bool
  3111 ConstructAbstract(JSContext* cx,
  3112                   unsigned argc,
  3113                   jsval* vp)
  3115   // Calling an abstract base class constructor is disallowed.
  3116   JS_ReportError(cx, "cannot construct from abstract type");
  3117   return false;
  3120 /*******************************************************************************
  3121 ** CType implementation
  3122 *******************************************************************************/
  3124 bool
  3125 CType::ConstructData(JSContext* cx,
  3126                      unsigned argc,
  3127                      jsval* vp)
  3129   CallArgs args = CallArgsFromVp(argc, vp);
  3130   // get the callee object...
  3131   RootedObject obj(cx, &args.callee());
  3132   if (!CType::IsCType(obj)) {
  3133     JS_ReportError(cx, "not a CType");
  3134     return false;
  3137   // How we construct the CData object depends on what type we represent.
  3138   // An instance 'd' of a CData object of type 't' has:
  3139   //   * [[Class]] "CData"
  3140   //   * __proto__ === t.prototype
  3141   switch (GetTypeCode(obj)) {
  3142   case TYPE_void_t:
  3143     JS_ReportError(cx, "cannot construct from void_t");
  3144     return false;
  3145   case TYPE_function:
  3146     JS_ReportError(cx, "cannot construct from FunctionType; use FunctionType.ptr instead");
  3147     return false;
  3148   case TYPE_pointer:
  3149     return PointerType::ConstructData(cx, obj, args);
  3150   case TYPE_array:
  3151     return ArrayType::ConstructData(cx, obj, args);
  3152   case TYPE_struct:
  3153     return StructType::ConstructData(cx, obj, args);
  3154   default:
  3155     return ConstructBasic(cx, obj, args);
  3159 bool
  3160 CType::ConstructBasic(JSContext* cx,
  3161                       HandleObject obj,
  3162                       const CallArgs& args)
  3164   if (args.length() > 1) {
  3165     JS_ReportError(cx, "CType constructor takes zero or one argument");
  3166     return false;
  3169   // construct a CData object
  3170   RootedObject result(cx, CData::Create(cx, obj, NullPtr(), nullptr, true));
  3171   if (!result)
  3172     return false;
  3174   if (args.length() == 1) {
  3175     if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result)))
  3176       return false;
  3179   args.rval().setObject(*result);
  3180   return true;
  3183 JSObject*
  3184 CType::Create(JSContext* cx,
  3185               HandleObject typeProto,
  3186               HandleObject dataProto,
  3187               TypeCode type,
  3188               JSString* name_,
  3189               jsval size_,
  3190               jsval align_,
  3191               ffi_type* ffiType)
  3193   RootedString name(cx, name_);
  3194   RootedValue size(cx, size_);
  3195   RootedValue align(cx, align_);
  3196   RootedObject parent(cx, JS_GetParent(typeProto));
  3197   JS_ASSERT(parent);
  3199   // Create a CType object with the properties and slots common to all CTypes.
  3200   // Each type object 't' has:
  3201   //   * [[Class]] "CType"
  3202   //   * __proto__ === 'typeProto'; one of ctypes.{CType,PointerType,ArrayType,
  3203   //     StructType}.prototype
  3204   //   * A constructor which creates and returns a CData object, containing
  3205   //     binary data of the given type.
  3206   //   * 'prototype' property:
  3207   //     * [[Class]] "CDataProto"
  3208   //     * __proto__ === 'dataProto'; an object containing properties and
  3209   //       functions common to all CData objects of types derived from
  3210   //       'typeProto'. (For instance, this could be ctypes.CData.prototype
  3211   //       for simple types, or something representing structs for StructTypes.)
  3212   //     * 'constructor' property === 't'
  3213   //     * Additional properties specified by 'ps', as appropriate for the
  3214   //       specific type instance 't'.
  3215   RootedObject typeObj(cx, JS_NewObject(cx, &sCTypeClass, typeProto, parent));
  3216   if (!typeObj)
  3217     return nullptr;
  3219   // Set up the reserved slots.
  3220   JS_SetReservedSlot(typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type));
  3221   if (ffiType)
  3222     JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType));
  3223   if (name)
  3224     JS_SetReservedSlot(typeObj, SLOT_NAME, STRING_TO_JSVAL(name));
  3225   JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
  3226   JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
  3228   if (dataProto) {
  3229     // Set up the 'prototype' and 'prototype.constructor' properties.
  3230     RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, parent));
  3231     if (!prototype)
  3232       return nullptr;
  3234     if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
  3235                            JSPROP_READONLY | JSPROP_PERMANENT))
  3236       return nullptr;
  3238     // Set the 'prototype' object.
  3239     //if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
  3240     //  return nullptr;
  3241     JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
  3244   if (!JS_FreezeObject(cx, typeObj))
  3245     return nullptr;
  3247   // Assert a sanity check on size and alignment: size % alignment should always
  3248   // be zero.
  3249   JS_ASSERT_IF(IsSizeDefined(typeObj),
  3250                GetSize(typeObj) % GetAlignment(typeObj) == 0);
  3252   return typeObj;
  3255 JSObject*
  3256 CType::DefineBuiltin(JSContext* cx,
  3257                      JSObject* parent_,
  3258                      const char* propName,
  3259                      JSObject* typeProto_,
  3260                      JSObject* dataProto_,
  3261                      const char* name,
  3262                      TypeCode type,
  3263                      jsval size_,
  3264                      jsval align_,
  3265                      ffi_type* ffiType)
  3267   RootedObject parent(cx, parent_);
  3268   RootedObject typeProto(cx, typeProto_);
  3269   RootedObject dataProto(cx, dataProto_);
  3270   RootedValue size(cx, size_);
  3271   RootedValue align(cx, align_);
  3273   RootedString nameStr(cx, JS_NewStringCopyZ(cx, name));
  3274   if (!nameStr)
  3275     return nullptr;
  3277   // Create a new CType object with the common properties and slots.
  3278   RootedObject typeObj(cx, Create(cx, typeProto, dataProto, type, nameStr, size, align, ffiType));
  3279   if (!typeObj)
  3280     return nullptr;
  3282   // Define the CType as a 'propName' property on 'parent'.
  3283   if (!JS_DefineProperty(cx, parent, propName, typeObj,
  3284                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  3285     return nullptr;
  3287   return typeObj;
  3290 void
  3291 CType::Finalize(JSFreeOp *fop, JSObject* obj)
  3293   // Make sure our TypeCode slot is legit. If it's not, bail.
  3294   jsval slot = JS_GetReservedSlot(obj, SLOT_TYPECODE);
  3295   if (JSVAL_IS_VOID(slot))
  3296     return;
  3298   // The contents of our slots depends on what kind of type we are.
  3299   switch (TypeCode(JSVAL_TO_INT(slot))) {
  3300   case TYPE_function: {
  3301     // Free the FunctionInfo.
  3302     slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
  3303     if (!JSVAL_IS_VOID(slot))
  3304       FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
  3305     break;
  3308   case TYPE_struct: {
  3309     // Free the FieldInfoHash table.
  3310     slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
  3311     if (!JSVAL_IS_VOID(slot)) {
  3312       void* info = JSVAL_TO_PRIVATE(slot);
  3313       FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
  3317     // Fall through.
  3318   case TYPE_array: {
  3319     // Free the ffi_type info.
  3320     slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
  3321     if (!JSVAL_IS_VOID(slot)) {
  3322       ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
  3323       FreeOp::get(fop)->free_(ffiType->elements);
  3324       FreeOp::get(fop)->delete_(ffiType);
  3327     break;
  3329   default:
  3330     // Nothing to do here.
  3331     break;
  3335 void
  3336 CType::Trace(JSTracer* trc, JSObject* obj)
  3338   // Make sure our TypeCode slot is legit. If it's not, bail.
  3339   jsval slot = obj->getSlot(SLOT_TYPECODE);
  3340   if (JSVAL_IS_VOID(slot))
  3341     return;
  3343   // The contents of our slots depends on what kind of type we are.
  3344   switch (TypeCode(JSVAL_TO_INT(slot))) {
  3345   case TYPE_struct: {
  3346     slot = obj->getReservedSlot(SLOT_FIELDINFO);
  3347     if (JSVAL_IS_VOID(slot))
  3348       return;
  3350     FieldInfoHash* fields =
  3351       static_cast<FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
  3352     for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
  3353       JSString *key = e.front().key();
  3354       JS_CallStringTracer(trc, &key, "fieldName");
  3355       if (key != e.front().key())
  3356           e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
  3357       JS_CallHeapObjectTracer(trc, &e.front().value().mType, "fieldType");
  3360     break;
  3362   case TYPE_function: {
  3363     // Check if we have a FunctionInfo.
  3364     slot = obj->getReservedSlot(SLOT_FNINFO);
  3365     if (JSVAL_IS_VOID(slot))
  3366       return;
  3368     FunctionInfo* fninfo = static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
  3369     JS_ASSERT(fninfo);
  3371     // Identify our objects to the tracer.
  3372     JS_CallHeapObjectTracer(trc, &fninfo->mABI, "abi");
  3373     JS_CallHeapObjectTracer(trc, &fninfo->mReturnType, "returnType");
  3374     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i)
  3375       JS_CallHeapObjectTracer(trc, &fninfo->mArgTypes[i], "argType");
  3377     break;
  3379   default:
  3380     // Nothing to do here.
  3381     break;
  3385 bool
  3386 CType::IsCType(JSObject* obj)
  3388   return JS_GetClass(obj) == &sCTypeClass;
  3391 bool
  3392 CType::IsCTypeProto(JSObject* obj)
  3394   return JS_GetClass(obj) == &sCTypeProtoClass;
  3397 TypeCode
  3398 CType::GetTypeCode(JSObject* typeObj)
  3400   JS_ASSERT(IsCType(typeObj));
  3402   jsval result = JS_GetReservedSlot(typeObj, SLOT_TYPECODE);
  3403   return TypeCode(JSVAL_TO_INT(result));
  3406 bool
  3407 CType::TypesEqual(JSObject* t1, JSObject* t2)
  3409   JS_ASSERT(IsCType(t1) && IsCType(t2));
  3411   // Fast path: check for object equality.
  3412   if (t1 == t2)
  3413     return true;
  3415   // First, perform shallow comparison.
  3416   TypeCode c1 = GetTypeCode(t1);
  3417   TypeCode c2 = GetTypeCode(t2);
  3418   if (c1 != c2)
  3419     return false;
  3421   // Determine whether the types require shallow or deep comparison.
  3422   switch (c1) {
  3423   case TYPE_pointer: {
  3424     // Compare base types.
  3425     JSObject* b1 = PointerType::GetBaseType(t1);
  3426     JSObject* b2 = PointerType::GetBaseType(t2);
  3427     return TypesEqual(b1, b2);
  3429   case TYPE_function: {
  3430     FunctionInfo* f1 = FunctionType::GetFunctionInfo(t1);
  3431     FunctionInfo* f2 = FunctionType::GetFunctionInfo(t2);
  3433     // Compare abi, return type, and argument types.
  3434     if (f1->mABI != f2->mABI)
  3435       return false;
  3437     if (!TypesEqual(f1->mReturnType, f2->mReturnType))
  3438       return false;
  3440     if (f1->mArgTypes.length() != f2->mArgTypes.length())
  3441       return false;
  3443     if (f1->mIsVariadic != f2->mIsVariadic)
  3444       return false;
  3446     for (size_t i = 0; i < f1->mArgTypes.length(); ++i) {
  3447       if (!TypesEqual(f1->mArgTypes[i], f2->mArgTypes[i]))
  3448         return false;
  3451     return true;
  3453   case TYPE_array: {
  3454     // Compare length, then base types.
  3455     // An undefined length array matches other undefined length arrays.
  3456     size_t s1 = 0, s2 = 0;
  3457     bool d1 = ArrayType::GetSafeLength(t1, &s1);
  3458     bool d2 = ArrayType::GetSafeLength(t2, &s2);
  3459     if (d1 != d2 || (d1 && s1 != s2))
  3460       return false;
  3462     JSObject* b1 = ArrayType::GetBaseType(t1);
  3463     JSObject* b2 = ArrayType::GetBaseType(t2);
  3464     return TypesEqual(b1, b2);
  3466   case TYPE_struct:
  3467     // Require exact type object equality.
  3468     return false;
  3469   default:
  3470     // Shallow comparison is sufficient.
  3471     return true;
  3475 bool
  3476 CType::GetSafeSize(JSObject* obj, size_t* result)
  3478   JS_ASSERT(CType::IsCType(obj));
  3480   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  3482   // The "size" property can be an int, a double, or JSVAL_VOID
  3483   // (for arrays of undefined length), and must always fit in a size_t.
  3484   if (JSVAL_IS_INT(size)) {
  3485     *result = JSVAL_TO_INT(size);
  3486     return true;
  3488   if (JSVAL_IS_DOUBLE(size)) {
  3489     *result = Convert<size_t>(JSVAL_TO_DOUBLE(size));
  3490     return true;
  3493   JS_ASSERT(JSVAL_IS_VOID(size));
  3494   return false;
  3497 size_t
  3498 CType::GetSize(JSObject* obj)
  3500   JS_ASSERT(CType::IsCType(obj));
  3502   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  3504   JS_ASSERT(!JSVAL_IS_VOID(size));
  3506   // The "size" property can be an int, a double, or JSVAL_VOID
  3507   // (for arrays of undefined length), and must always fit in a size_t.
  3508   // For callers who know it can never be JSVAL_VOID, return a size_t directly.
  3509   if (JSVAL_IS_INT(size))
  3510     return JSVAL_TO_INT(size);
  3511   return Convert<size_t>(JSVAL_TO_DOUBLE(size));
  3514 bool
  3515 CType::IsSizeDefined(JSObject* obj)
  3517   JS_ASSERT(CType::IsCType(obj));
  3519   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
  3521   // The "size" property can be an int, a double, or JSVAL_VOID
  3522   // (for arrays of undefined length), and must always fit in a size_t.
  3523   JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
  3524   return !JSVAL_IS_VOID(size);
  3527 size_t
  3528 CType::GetAlignment(JSObject* obj)
  3530   JS_ASSERT(CType::IsCType(obj));
  3532   jsval slot = JS_GetReservedSlot(obj, SLOT_ALIGN);
  3533   return static_cast<size_t>(JSVAL_TO_INT(slot));
  3536 ffi_type*
  3537 CType::GetFFIType(JSContext* cx, JSObject* obj)
  3539   JS_ASSERT(CType::IsCType(obj));
  3541   jsval slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
  3543   if (!JSVAL_IS_VOID(slot)) {
  3544     return static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
  3547   AutoPtr<ffi_type> result;
  3548   switch (CType::GetTypeCode(obj)) {
  3549   case TYPE_array:
  3550     result = ArrayType::BuildFFIType(cx, obj);
  3551     break;
  3553   case TYPE_struct:
  3554     result = StructType::BuildFFIType(cx, obj);
  3555     break;
  3557   default:
  3558     MOZ_ASSUME_UNREACHABLE("simple types must have an ffi_type");
  3561   if (!result)
  3562     return nullptr;
  3563   JS_SetReservedSlot(obj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(result.get()));
  3564   return result.forget();
  3567 JSString*
  3568 CType::GetName(JSContext* cx, HandleObject obj)
  3570   JS_ASSERT(CType::IsCType(obj));
  3572   jsval string = JS_GetReservedSlot(obj, SLOT_NAME);
  3573   if (!JSVAL_IS_VOID(string))
  3574     return JSVAL_TO_STRING(string);
  3576   // Build the type name lazily.
  3577   JSString* name = BuildTypeName(cx, obj);
  3578   if (!name)
  3579     return nullptr;
  3580   JS_SetReservedSlot(obj, SLOT_NAME, STRING_TO_JSVAL(name));
  3581   return name;
  3584 JSObject*
  3585 CType::GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot)
  3587   // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot
  3588   // on the type constructor.
  3589   jsval protoslot = js::GetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO);
  3590   JSObject* proto = &protoslot.toObject();
  3591   JS_ASSERT(proto);
  3592   JS_ASSERT(CType::IsCTypeProto(proto));
  3594   // Get the desired prototype.
  3595   jsval result = JS_GetReservedSlot(proto, slot);
  3596   return &result.toObject();
  3599 JSObject*
  3600 CType::GetProtoFromType(JSContext* cx, JSObject* objArg, CTypeProtoSlot slot)
  3602   JS_ASSERT(IsCType(objArg));
  3603   RootedObject obj(cx, objArg);
  3605   // Get the prototype of the type object.
  3606   RootedObject proto(cx);
  3607   if (!JS_GetPrototype(cx, obj, &proto))
  3608     return nullptr;
  3609   JS_ASSERT(proto);
  3610   JS_ASSERT(CType::IsCTypeProto(proto));
  3612   // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype.
  3613   jsval result = JS_GetReservedSlot(proto, slot);
  3614   JS_ASSERT(!JSVAL_IS_PRIMITIVE(result));
  3615   return JSVAL_TO_OBJECT(result);
  3618 bool
  3619 CType::IsCTypeOrProto(HandleValue v)
  3621   if (!v.isObject())
  3622     return false;
  3623   JSObject* obj = &v.toObject();
  3624   return CType::IsCType(obj) || CType::IsCTypeProto(obj);
  3627 bool
  3628 CType::PrototypeGetter(JSContext* cx, JS::CallArgs args)
  3630   RootedObject obj(cx, &args.thisv().toObject());
  3631   unsigned slot = CType::IsCTypeProto(obj) ? (unsigned) SLOT_OURDATAPROTO
  3632                                            : (unsigned) SLOT_PROTO;
  3633   args.rval().set(JS_GetReservedSlot(obj, slot));
  3634   MOZ_ASSERT(args.rval().isObject() || args.rval().isUndefined());
  3635   return true;
  3638 bool
  3639 CType::IsCType(HandleValue v)
  3641   return v.isObject() && CType::IsCType(&v.toObject());
  3644 bool
  3645 CType::NameGetter(JSContext* cx, JS::CallArgs args)
  3647   RootedObject obj(cx, &args.thisv().toObject());
  3648   JSString* name = CType::GetName(cx, obj);
  3649   if (!name)
  3650     return false;
  3652   args.rval().setString(name);
  3653   return true;
  3656 bool
  3657 CType::SizeGetter(JSContext* cx, JS::CallArgs args)
  3659   RootedObject obj(cx, &args.thisv().toObject());
  3660   args.rval().set(JS_GetReservedSlot(obj, SLOT_SIZE));
  3661   MOZ_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
  3662   return true;
  3665 bool
  3666 CType::PtrGetter(JSContext* cx, JS::CallArgs args)
  3668   RootedObject obj(cx, &args.thisv().toObject());
  3669   JSObject* pointerType = PointerType::CreateInternal(cx, obj);
  3670   if (!pointerType)
  3671     return false;
  3673   args.rval().setObject(*pointerType);
  3674   return true;
  3677 bool
  3678 CType::CreateArray(JSContext* cx, unsigned argc, jsval* vp)
  3680   CallArgs args = CallArgsFromVp(argc, vp);
  3681   RootedObject baseType(cx, JS_THIS_OBJECT(cx, vp));
  3682   if (!baseType)
  3683     return false;
  3684   if (!CType::IsCType(baseType)) {
  3685     JS_ReportError(cx, "not a CType");
  3686     return false;
  3689   // Construct and return a new ArrayType object.
  3690   if (args.length() > 1) {
  3691     JS_ReportError(cx, "array takes zero or one argument");
  3692     return false;
  3695   // Convert the length argument to a size_t.
  3696   size_t length = 0;
  3697   if (args.length() == 1 && !jsvalToSize(cx, args[0], false, &length)) {
  3698     JS_ReportError(cx, "argument must be a nonnegative integer");
  3699     return false;
  3702   JSObject* result = ArrayType::CreateInternal(cx, baseType, length, args.length() == 1);
  3703   if (!result)
  3704     return false;
  3706   args.rval().setObject(*result);
  3707   return true;
  3710 bool
  3711 CType::ToString(JSContext* cx, unsigned argc, jsval* vp)
  3713   CallArgs args = CallArgsFromVp(argc, vp);
  3714   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  3715   if (!obj)
  3716     return false;
  3717   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
  3718     JS_ReportError(cx, "not a CType");
  3719     return false;
  3722   // Create the appropriate string depending on whether we're sCTypeClass or
  3723   // sCTypeProtoClass.
  3724   JSString* result;
  3725   if (CType::IsCType(obj)) {
  3726     AutoString type;
  3727     AppendString(type, "type ");
  3728     AppendString(type, GetName(cx, obj));
  3729     result = NewUCString(cx, type);
  3731   else {
  3732     result = JS_NewStringCopyZ(cx, "[CType proto object]");
  3734   if (!result)
  3735     return false;
  3737   args.rval().setString(result);
  3738   return true;
  3741 bool
  3742 CType::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  3744   CallArgs args = CallArgsFromVp(argc, vp);
  3745   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  3746   if (!obj)
  3747     return false;
  3748   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj))
  3750     JS_ReportError(cx, "not a CType");
  3751     return false;
  3754   // Create the appropriate string depending on whether we're sCTypeClass or
  3755   // sCTypeProtoClass.
  3756   JSString* result;
  3757   if (CType::IsCType(obj)) {
  3758     AutoString source;
  3759     BuildTypeSource(cx, obj, false, source);
  3760     result = NewUCString(cx, source);
  3761   } else {
  3762     result = JS_NewStringCopyZ(cx, "[CType proto object]");
  3764   if (!result)
  3765     return false;
  3767   args.rval().setString(result);
  3768   return true;
  3771 bool
  3772 CType::HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
  3774   JS_ASSERT(CType::IsCType(obj));
  3776   jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO);
  3777   JS::Rooted<JSObject*> prototype(cx, &slot.toObject());
  3778   JS_ASSERT(prototype);
  3779   JS_ASSERT(CData::IsCDataProto(prototype));
  3781   *bp = false;
  3782   if (JSVAL_IS_PRIMITIVE(v))
  3783     return true;
  3785   RootedObject proto(cx, &v.toObject());
  3786   for (;;) {
  3787     if (!JS_GetPrototype(cx, proto, &proto))
  3788       return false;
  3789     if (!proto)
  3790       break;
  3791     if (proto == prototype) {
  3792       *bp = true;
  3793       break;
  3796   return true;
  3799 static JSObject*
  3800 CType::GetGlobalCTypes(JSContext* cx, JSObject* objArg)
  3802   JS_ASSERT(CType::IsCType(objArg));
  3804   RootedObject obj(cx, objArg);
  3805   RootedObject objTypeProto(cx);
  3806   if (!JS_GetPrototype(cx, obj, &objTypeProto))
  3807     return nullptr;
  3808   JS_ASSERT(objTypeProto);
  3809   JS_ASSERT(CType::IsCTypeProto(objTypeProto));
  3811   jsval valCTypes = JS_GetReservedSlot(objTypeProto, SLOT_CTYPES);
  3812   JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
  3814   JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
  3815   return &valCTypes.toObject();
  3818 /*******************************************************************************
  3819 ** ABI implementation
  3820 *******************************************************************************/
  3822 bool
  3823 ABI::IsABI(JSObject* obj)
  3825   return JS_GetClass(obj) == &sCABIClass;
  3828 bool
  3829 ABI::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  3831   CallArgs args = CallArgsFromVp(argc, vp);
  3832   if (args.length() != 0) {
  3833     JS_ReportError(cx, "toSource takes zero arguments");
  3834     return false;
  3837   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  3838   if (!obj)
  3839     return false;
  3840   if (!ABI::IsABI(obj)) {
  3841     JS_ReportError(cx, "not an ABI");
  3842     return false;
  3845   JSString* result;
  3846   switch (GetABICode(obj)) {
  3847     case ABI_DEFAULT:
  3848       result = JS_NewStringCopyZ(cx, "ctypes.default_abi");
  3849       break;
  3850     case ABI_STDCALL:
  3851       result = JS_NewStringCopyZ(cx, "ctypes.stdcall_abi");
  3852       break;
  3853     case ABI_WINAPI:
  3854       result = JS_NewStringCopyZ(cx, "ctypes.winapi_abi");
  3855       break;
  3856     default:
  3857       JS_ReportError(cx, "not a valid ABICode");
  3858       return false;
  3860   if (!result)
  3861     return false;
  3863   args.rval().setString(result);
  3864   return true;
  3868 /*******************************************************************************
  3869 ** PointerType implementation
  3870 *******************************************************************************/
  3872 bool
  3873 PointerType::Create(JSContext* cx, unsigned argc, jsval* vp)
  3875   CallArgs args = CallArgsFromVp(argc, vp);
  3876   // Construct and return a new PointerType object.
  3877   if (args.length() != 1) {
  3878     JS_ReportError(cx, "PointerType takes one argument");
  3879     return false;
  3882   jsval arg = args[0];
  3883   RootedObject obj(cx);
  3884   if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(obj = &arg.toObject())) {
  3885     JS_ReportError(cx, "first argument must be a CType");
  3886     return false;
  3889   JSObject* result = CreateInternal(cx, obj);
  3890   if (!result)
  3891     return false;
  3893   args.rval().setObject(*result);
  3894   return true;
  3897 JSObject*
  3898 PointerType::CreateInternal(JSContext* cx, HandleObject baseType)
  3900   // check if we have a cached PointerType on our base CType.
  3901   jsval slot = JS_GetReservedSlot(baseType, SLOT_PTR);
  3902   if (!slot.isUndefined())
  3903     return &slot.toObject();
  3905   // Get ctypes.PointerType.prototype and the common prototype for CData objects
  3906   // of this type, or ctypes.FunctionType.prototype for function pointers.
  3907   CTypeProtoSlot slotId = CType::GetTypeCode(baseType) == TYPE_function ?
  3908     SLOT_FUNCTIONDATAPROTO : SLOT_POINTERDATAPROTO;
  3909   RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, slotId));
  3910   if (!dataProto)
  3911     return nullptr;
  3912   RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO));
  3913   if (!typeProto)
  3914     return nullptr;
  3916   // Create a new CType object with the common properties and slots.
  3917   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer,
  3918                         nullptr, INT_TO_JSVAL(sizeof(void*)),
  3919                         INT_TO_JSVAL(ffi_type_pointer.alignment),
  3920                         &ffi_type_pointer);
  3921   if (!typeObj)
  3922     return nullptr;
  3924   // Set the target type. (This will be 'null' for an opaque pointer type.)
  3925   JS_SetReservedSlot(typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType));
  3927   // Finally, cache our newly-created PointerType on our pointed-to CType.
  3928   JS_SetReservedSlot(baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj));
  3930   return typeObj;
  3933 bool
  3934 PointerType::ConstructData(JSContext* cx,
  3935                            HandleObject obj,
  3936                            const CallArgs& args)
  3938   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_pointer) {
  3939     JS_ReportError(cx, "not a PointerType");
  3940     return false;
  3943   if (args.length() > 3) {
  3944     JS_ReportError(cx, "constructor takes 0, 1, 2, or 3 arguments");
  3945     return false;
  3948   RootedObject result(cx, CData::Create(cx, obj, NullPtr(), nullptr, true));
  3949   if (!result)
  3950     return false;
  3952   // Set return value early, must not observe *vp after
  3953   args.rval().setObject(*result);
  3955   // There are 3 things that we might be creating here:
  3956   // 1 - A null pointer (no arguments)
  3957   // 2 - An initialized pointer (1 argument)
  3958   // 3 - A closure (1-3 arguments)
  3959   //
  3960   // The API doesn't give us a perfect way to distinguish 2 and 3, but the
  3961   // heuristics we use should be fine.
  3963   //
  3964   // Case 1 - Null pointer
  3965   //
  3966   if (args.length() == 0)
  3967     return true;
  3969   // Analyze the arguments a bit to decide what to do next.
  3970   RootedObject baseObj(cx, PointerType::GetBaseType(obj));
  3971   bool looksLikeClosure = CType::GetTypeCode(baseObj) == TYPE_function &&
  3972                           args[0].isObject() &&
  3973                           JS_ObjectIsCallable(cx, &args[0].toObject());
  3975   //
  3976   // Case 2 - Initialized pointer
  3977   //
  3978   if (!looksLikeClosure) {
  3979     if (args.length() != 1) {
  3980       JS_ReportError(cx, "first argument must be a function");
  3981       return false;
  3983     return ExplicitConvert(cx, args[0], obj, CData::GetData(result));
  3986   //
  3987   // Case 3 - Closure
  3988   //
  3990   // The second argument is an optional 'this' parameter with which to invoke
  3991   // the given js function. Callers may leave this blank, or pass null if they
  3992   // wish to pass the third argument.
  3993   RootedObject thisObj(cx, nullptr);
  3994   if (args.length() >= 2) {
  3995     if (args[1].isNull()) {
  3996       thisObj = nullptr;
  3997     } else if (!JSVAL_IS_PRIMITIVE(args[1])) {
  3998       thisObj = &args[1].toObject();
  3999     } else if (!JS_ValueToObject(cx, args[1], &thisObj)) {
  4000       return false;
  4004   // The third argument is an optional error sentinel that js-ctypes will return
  4005   // if an exception is raised while executing the closure. The type must match
  4006   // the return type of the callback.
  4007   jsval errVal = JSVAL_VOID;
  4008   if (args.length() == 3)
  4009     errVal = args[2];
  4011   RootedObject fnObj(cx, &args[0].toObject());
  4012   return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj, errVal);
  4015 JSObject*
  4016 PointerType::GetBaseType(JSObject* obj)
  4018   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_pointer);
  4020   jsval type = JS_GetReservedSlot(obj, SLOT_TARGET_T);
  4021   JS_ASSERT(!type.isNull());
  4022   return &type.toObject();
  4025 bool
  4026 PointerType::IsPointerType(HandleValue v)
  4028   if (!v.isObject())
  4029     return false;
  4030   JSObject* obj = &v.toObject();
  4031   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_pointer;
  4034 bool
  4035 PointerType::IsPointer(HandleValue v)
  4037   if (!v.isObject())
  4038     return false;
  4039   JSObject* obj = &v.toObject();
  4040   return CData::IsCData(obj) && CType::GetTypeCode(CData::GetCType(obj)) == TYPE_pointer;
  4043 bool
  4044 PointerType::TargetTypeGetter(JSContext* cx, JS::CallArgs args)
  4046   RootedObject obj(cx, &args.thisv().toObject());
  4047   args.rval().set(JS_GetReservedSlot(obj, SLOT_TARGET_T));
  4048   MOZ_ASSERT(args.rval().isObject());
  4049   return true;
  4052 bool
  4053 PointerType::IsNull(JSContext* cx, unsigned argc, jsval* vp)
  4055   CallArgs args = CallArgsFromVp(argc, vp);
  4056   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  4057   if (!obj)
  4058     return false;
  4059   if (!CData::IsCData(obj)) {
  4060     JS_ReportError(cx, "not a CData");
  4061     return false;
  4064   // Get pointer type and base type.
  4065   JSObject* typeObj = CData::GetCType(obj);
  4066   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  4067     JS_ReportError(cx, "not a PointerType");
  4068     return false;
  4071   void* data = *static_cast<void**>(CData::GetData(obj));
  4072   args.rval().setBoolean(data == nullptr);
  4073   return true;
  4076 bool
  4077 PointerType::OffsetBy(JSContext* cx, const CallArgs& args, int offset)
  4079   JSObject* obj = JS_THIS_OBJECT(cx, args.base());
  4080   if (!obj)
  4081     return false;
  4082   if (!CData::IsCData(obj)) {
  4083     JS_ReportError(cx, "not a CData");
  4084     return false;
  4087   RootedObject typeObj(cx, CData::GetCType(obj));
  4088   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  4089     JS_ReportError(cx, "not a PointerType");
  4090     return false;
  4093   RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
  4094   if (!CType::IsSizeDefined(baseType)) {
  4095     JS_ReportError(cx, "cannot modify pointer of undefined size");
  4096     return false;
  4099   size_t elementSize = CType::GetSize(baseType);
  4100   char* data = static_cast<char*>(*static_cast<void**>(CData::GetData(obj)));
  4101   void* address = data + offset * elementSize;
  4103   // Create a PointerType CData object containing the new address.
  4104   JSObject* result = CData::Create(cx, typeObj, NullPtr(), &address, true);
  4105   if (!result)
  4106     return false;
  4108   args.rval().setObject(*result);
  4109   return true;
  4112 bool
  4113 PointerType::Increment(JSContext* cx, unsigned argc, jsval* vp)
  4115   CallArgs args = CallArgsFromVp(argc, vp);
  4116   return OffsetBy(cx, args, 1);
  4119 bool
  4120 PointerType::Decrement(JSContext* cx, unsigned argc, jsval* vp)
  4122   CallArgs args = CallArgsFromVp(argc, vp);
  4123   return OffsetBy(cx, args, -1);
  4126 bool
  4127 PointerType::ContentsGetter(JSContext* cx, JS::CallArgs args)
  4129   RootedObject obj(cx, &args.thisv().toObject());
  4130   RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
  4131   if (!CType::IsSizeDefined(baseType)) {
  4132     JS_ReportError(cx, "cannot get contents of undefined size");
  4133     return false;
  4136   void* data = *static_cast<void**>(CData::GetData(obj));
  4137   if (data == nullptr) {
  4138     JS_ReportError(cx, "cannot read contents of null pointer");
  4139     return false;
  4142   RootedValue result(cx);
  4143   if (!ConvertToJS(cx, baseType, NullPtr(), data, false, false, result.address()))
  4144     return false;
  4146   args.rval().set(result);
  4147   return true;
  4150 bool
  4151 PointerType::ContentsSetter(JSContext* cx, JS::CallArgs args)
  4153   RootedObject obj(cx, &args.thisv().toObject());
  4154   RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
  4155   if (!CType::IsSizeDefined(baseType)) {
  4156     JS_ReportError(cx, "cannot set contents of undefined size");
  4157     return false;
  4160   void* data = *static_cast<void**>(CData::GetData(obj));
  4161   if (data == nullptr) {
  4162     JS_ReportError(cx, "cannot write contents to null pointer");
  4163     return false;
  4166   args.rval().setUndefined();
  4167   return ImplicitConvert(cx, args.get(0), baseType, data, false, nullptr);
  4170 /*******************************************************************************
  4171 ** ArrayType implementation
  4172 *******************************************************************************/
  4174 bool
  4175 ArrayType::Create(JSContext* cx, unsigned argc, jsval* vp)
  4177   CallArgs args = CallArgsFromVp(argc, vp);
  4178   // Construct and return a new ArrayType object.
  4179   if (args.length() < 1 || args.length() > 2) {
  4180     JS_ReportError(cx, "ArrayType takes one or two arguments");
  4181     return false;
  4184   if (JSVAL_IS_PRIMITIVE(args[0]) ||
  4185       !CType::IsCType(&args[0].toObject())) {
  4186     JS_ReportError(cx, "first argument must be a CType");
  4187     return false;
  4190   // Convert the length argument to a size_t.
  4191   size_t length = 0;
  4192   if (args.length() == 2 && !jsvalToSize(cx, args[1], false, &length)) {
  4193     JS_ReportError(cx, "second argument must be a nonnegative integer");
  4194     return false;
  4197   RootedObject baseType(cx, &args[0].toObject());
  4198   JSObject* result = CreateInternal(cx, baseType, length, args.length() == 2);
  4199   if (!result)
  4200     return false;
  4202   args.rval().setObject(*result);
  4203   return true;
  4206 JSObject*
  4207 ArrayType::CreateInternal(JSContext* cx,
  4208                           HandleObject baseType,
  4209                           size_t length,
  4210                           bool lengthDefined)
  4212   // Get ctypes.ArrayType.prototype and the common prototype for CData objects
  4213   // of this type, from ctypes.CType.prototype.
  4214   RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYPROTO));
  4215   if (!typeProto)
  4216     return nullptr;
  4217   RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYDATAPROTO));
  4218   if (!dataProto)
  4219     return nullptr;
  4221   // Determine the size of the array from the base type, if possible.
  4222   // The size of the base type must be defined.
  4223   // If our length is undefined, both our size and length will be undefined.
  4224   size_t baseSize;
  4225   if (!CType::GetSafeSize(baseType, &baseSize)) {
  4226     JS_ReportError(cx, "base size must be defined");
  4227     return nullptr;
  4230   RootedValue sizeVal(cx, JSVAL_VOID);
  4231   RootedValue lengthVal(cx, JSVAL_VOID);
  4232   if (lengthDefined) {
  4233     // Check for overflow, and convert to an int or double as required.
  4234     size_t size = length * baseSize;
  4235     if (length > 0 && size / length != baseSize) {
  4236       JS_ReportError(cx, "size overflow");
  4237       return nullptr;
  4239     if (!SizeTojsval(cx, size, sizeVal.address()) ||
  4240         !SizeTojsval(cx, length, lengthVal.address()))
  4241       return nullptr;
  4244   size_t align = CType::GetAlignment(baseType);
  4246   // Create a new CType object with the common properties and slots.
  4247   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_array, nullptr,
  4248                         sizeVal, INT_TO_JSVAL(align), nullptr);
  4249   if (!typeObj)
  4250     return nullptr;
  4252   // Set the element type.
  4253   JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType));
  4255   // Set the length.
  4256   JS_SetReservedSlot(typeObj, SLOT_LENGTH, lengthVal);
  4258   return typeObj;
  4261 bool
  4262 ArrayType::ConstructData(JSContext* cx,
  4263                          HandleObject obj_,
  4264                          const CallArgs& args)
  4266   RootedObject obj(cx, obj_); // Make a mutable version
  4268   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
  4269     JS_ReportError(cx, "not an ArrayType");
  4270     return false;
  4273   // Decide whether we have an object to initialize from. We'll override this
  4274   // if we get a length argument instead.
  4275   bool convertObject = args.length() == 1;
  4277   // Check if we're an array of undefined length. If we are, allow construction
  4278   // with a length argument, or with an actual JS array.
  4279   if (CType::IsSizeDefined(obj)) {
  4280     if (args.length() > 1) {
  4281       JS_ReportError(cx, "constructor takes zero or one argument");
  4282       return false;
  4285   } else {
  4286     if (args.length() != 1) {
  4287       JS_ReportError(cx, "constructor takes one argument");
  4288       return false;
  4291     RootedObject baseType(cx, GetBaseType(obj));
  4293     size_t length;
  4294     if (jsvalToSize(cx, args[0], false, &length)) {
  4295       // Have a length, rather than an object to initialize from.
  4296       convertObject = false;
  4298     } else if (!JSVAL_IS_PRIMITIVE(args[0])) {
  4299       // We were given an object with a .length property.
  4300       // This could be a JS array, or a CData array.
  4301       RootedObject arg(cx, &args[0].toObject());
  4302       RootedValue lengthVal(cx);
  4303       if (!JS_GetProperty(cx, arg, "length", &lengthVal) ||
  4304           !jsvalToSize(cx, lengthVal, false, &length)) {
  4305         JS_ReportError(cx, "argument must be an array object or length");
  4306         return false;
  4309     } else if (args[0].isString()) {
  4310       // We were given a string. Size the array to the appropriate length,
  4311       // including space for the terminator.
  4312       JSString* sourceString = args[0].toString();
  4313       size_t sourceLength = sourceString->length();
  4314       const jschar* sourceChars = sourceString->getChars(cx);
  4315       if (!sourceChars)
  4316         return false;
  4318       switch (CType::GetTypeCode(baseType)) {
  4319       case TYPE_char:
  4320       case TYPE_signed_char:
  4321       case TYPE_unsigned_char: {
  4322         // Determine the UTF-8 length.
  4323         length = GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
  4324         if (length == (size_t) -1)
  4325           return false;
  4327         ++length;
  4328         break;
  4330       case TYPE_jschar:
  4331         length = sourceLength + 1;
  4332         break;
  4333       default:
  4334         return TypeError(cx, "array", args[0]);
  4337     } else {
  4338       JS_ReportError(cx, "argument must be an array object or length");
  4339       return false;
  4342     // Construct a new ArrayType of defined length, for the new CData object.
  4343     obj = CreateInternal(cx, baseType, length, true);
  4344     if (!obj)
  4345       return false;
  4348   JSObject* result = CData::Create(cx, obj, NullPtr(), nullptr, true);
  4349   if (!result)
  4350     return false;
  4352   args.rval().setObject(*result);
  4354   if (convertObject) {
  4355     if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result)))
  4356       return false;
  4359   return true;
  4362 JSObject*
  4363 ArrayType::GetBaseType(JSObject* obj)
  4365   JS_ASSERT(CType::IsCType(obj));
  4366   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  4368   jsval type = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
  4369   JS_ASSERT(!JSVAL_IS_NULL(type));
  4370   return &type.toObject();
  4373 bool
  4374 ArrayType::GetSafeLength(JSObject* obj, size_t* result)
  4376   JS_ASSERT(CType::IsCType(obj));
  4377   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  4379   jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
  4381   // The "length" property can be an int, a double, or JSVAL_VOID
  4382   // (for arrays of undefined length), and must always fit in a size_t.
  4383   if (length.isInt32()) {
  4384     *result = length.toInt32();;
  4385     return true;
  4387   if (length.isDouble()) {
  4388     *result = Convert<size_t>(length.toDouble());
  4389     return true;
  4392   JS_ASSERT(length.isUndefined());
  4393   return false;
  4396 size_t
  4397 ArrayType::GetLength(JSObject* obj)
  4399   JS_ASSERT(CType::IsCType(obj));
  4400   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  4402   jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
  4404   JS_ASSERT(!length.isUndefined());
  4406   // The "length" property can be an int, a double, or JSVAL_VOID
  4407   // (for arrays of undefined length), and must always fit in a size_t.
  4408   // For callers who know it can never be JSVAL_VOID, return a size_t directly.
  4409   if (length.isInt32())
  4410     return length.toInt32();;
  4411   return Convert<size_t>(length.toDouble());
  4414 ffi_type*
  4415 ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
  4417   JS_ASSERT(CType::IsCType(obj));
  4418   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
  4419   JS_ASSERT(CType::IsSizeDefined(obj));
  4421   JSObject* baseType = ArrayType::GetBaseType(obj);
  4422   ffi_type* ffiBaseType = CType::GetFFIType(cx, baseType);
  4423   if (!ffiBaseType)
  4424     return nullptr;
  4426   size_t length = ArrayType::GetLength(obj);
  4428   // Create an ffi_type to represent the array. This is necessary for the case
  4429   // where the array is part of a struct. Since libffi has no intrinsic
  4430   // support for array types, we approximate it by creating a struct type
  4431   // with elements of type 'baseType' and with appropriate size and alignment
  4432   // values. It would be nice to not do all the work of setting up 'elements',
  4433   // but some libffi platforms currently require that it be meaningful. I'm
  4434   // looking at you, x86_64.
  4435   AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
  4436   if (!ffiType) {
  4437     JS_ReportOutOfMemory(cx);
  4438     return nullptr;
  4441   ffiType->type = FFI_TYPE_STRUCT;
  4442   ffiType->size = CType::GetSize(obj);
  4443   ffiType->alignment = CType::GetAlignment(obj);
  4444   ffiType->elements = cx->pod_malloc<ffi_type*>(length + 1);
  4445   if (!ffiType->elements) {
  4446     JS_ReportAllocationOverflow(cx);
  4447     return nullptr;
  4450   for (size_t i = 0; i < length; ++i)
  4451     ffiType->elements[i] = ffiBaseType;
  4452   ffiType->elements[length] = nullptr;
  4454   return ffiType.forget();
  4457 bool
  4458 ArrayType::IsArrayType(HandleValue v)
  4460   if (!v.isObject())
  4461     return false;
  4462   JSObject* obj = &v.toObject();
  4463   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
  4466 bool
  4467 ArrayType::IsArrayOrArrayType(HandleValue v)
  4469   if (!v.isObject())
  4470     return false;
  4471   JSObject* obj = &v.toObject();
  4473    // Allow both CTypes and CDatas of the ArrayType persuasion by extracting the
  4474    // CType if we're dealing with a CData.
  4475   if (CData::IsCData(obj)) {
  4476     obj = CData::GetCType(obj);
  4478   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
  4481 bool
  4482 ArrayType::ElementTypeGetter(JSContext* cx, JS::CallArgs args)
  4484   RootedObject obj(cx, &args.thisv().toObject());
  4485   args.rval().set(JS_GetReservedSlot(obj, SLOT_ELEMENT_T));
  4486   MOZ_ASSERT(args.rval().isObject());
  4487   return true;
  4490 bool
  4491 ArrayType::LengthGetter(JSContext* cx, JS::CallArgs args)
  4493   JSObject *obj = &args.thisv().toObject();
  4495   // This getter exists for both CTypes and CDatas of the ArrayType persuasion.
  4496   // If we're dealing with a CData, get the CType from it.
  4497   if (CData::IsCData(obj))
  4498     obj = CData::GetCType(obj);
  4500   args.rval().set(JS_GetReservedSlot(obj, SLOT_LENGTH));
  4501   JS_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
  4502   return true;
  4505 bool
  4506 ArrayType::Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp)
  4508   // This should never happen, but we'll check to be safe.
  4509   if (!CData::IsCData(obj)) {
  4510     JS_ReportError(cx, "not a CData");
  4511     return false;
  4514   // Bail early if we're not an ArrayType. (This setter is present for all
  4515   // CData, regardless of CType.)
  4516   JSObject* typeObj = CData::GetCType(obj);
  4517   if (CType::GetTypeCode(typeObj) != TYPE_array)
  4518     return true;
  4520   // Convert the index to a size_t and bounds-check it.
  4521   size_t index;
  4522   size_t length = GetLength(typeObj);
  4523   bool ok = jsidToSize(cx, idval, true, &index);
  4524   int32_t dummy;
  4525   if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
  4526     // String either isn't a number, or doesn't fit in size_t.
  4527     // Chances are it's a regular property lookup, so return.
  4528     return true;
  4530   if (!ok || index >= length) {
  4531     JS_ReportError(cx, "invalid index");
  4532     return false;
  4535   RootedObject baseType(cx, GetBaseType(typeObj));
  4536   size_t elementSize = CType::GetSize(baseType);
  4537   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  4538   return ConvertToJS(cx, baseType, obj, data, false, false, vp.address());
  4541 bool
  4542 ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
  4544   // This should never happen, but we'll check to be safe.
  4545   if (!CData::IsCData(obj)) {
  4546     JS_ReportError(cx, "not a CData");
  4547     return false;
  4550   // Bail early if we're not an ArrayType. (This setter is present for all
  4551   // CData, regardless of CType.)
  4552   JSObject* typeObj = CData::GetCType(obj);
  4553   if (CType::GetTypeCode(typeObj) != TYPE_array)
  4554     return true;
  4556   // Convert the index to a size_t and bounds-check it.
  4557   size_t index;
  4558   size_t length = GetLength(typeObj);
  4559   bool ok = jsidToSize(cx, idval, true, &index);
  4560   int32_t dummy;
  4561   if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
  4562     // String either isn't a number, or doesn't fit in size_t.
  4563     // Chances are it's a regular property lookup, so return.
  4564     return true;
  4566   if (!ok || index >= length) {
  4567     JS_ReportError(cx, "invalid index");
  4568     return false;
  4571   JSObject* baseType = GetBaseType(typeObj);
  4572   size_t elementSize = CType::GetSize(baseType);
  4573   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  4574   return ImplicitConvert(cx, vp, baseType, data, false, nullptr);
  4577 bool
  4578 ArrayType::AddressOfElement(JSContext* cx, unsigned argc, jsval* vp)
  4580   CallArgs args = CallArgsFromVp(argc, vp);
  4581   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  4582   if (!obj)
  4583     return false;
  4584   if (!CData::IsCData(obj)) {
  4585     JS_ReportError(cx, "not a CData");
  4586     return false;
  4589   RootedObject typeObj(cx, CData::GetCType(obj));
  4590   if (CType::GetTypeCode(typeObj) != TYPE_array) {
  4591     JS_ReportError(cx, "not an ArrayType");
  4592     return false;
  4595   if (args.length() != 1) {
  4596     JS_ReportError(cx, "addressOfElement takes one argument");
  4597     return false;
  4600   RootedObject baseType(cx, GetBaseType(typeObj));
  4601   RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
  4602   if (!pointerType)
  4603     return false;
  4605   // Create a PointerType CData object containing null.
  4606   RootedObject result(cx, CData::Create(cx, pointerType, NullPtr(), nullptr, true));
  4607   if (!result)
  4608     return false;
  4610   args.rval().setObject(*result);
  4612   // Convert the index to a size_t and bounds-check it.
  4613   size_t index;
  4614   size_t length = GetLength(typeObj);
  4615   if (!jsvalToSize(cx, args[0], false, &index) ||
  4616       index >= length) {
  4617     JS_ReportError(cx, "invalid index");
  4618     return false;
  4621   // Manually set the pointer inside the object, so we skip the conversion step.
  4622   void** data = static_cast<void**>(CData::GetData(result));
  4623   size_t elementSize = CType::GetSize(baseType);
  4624   *data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
  4625   return true;
  4628 /*******************************************************************************
  4629 ** StructType implementation
  4630 *******************************************************************************/
  4632 // For a struct field descriptor 'val' of the form { name : type }, extract
  4633 // 'name' and 'type'.
  4634 static JSFlatString*
  4635 ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
  4637   if (JSVAL_IS_PRIMITIVE(val)) {
  4638     JS_ReportError(cx, "struct field descriptors require a valid name and type");
  4639     return nullptr;
  4642   RootedObject obj(cx, JSVAL_TO_OBJECT(val));
  4643   RootedObject iter(cx, JS_NewPropertyIterator(cx, obj));
  4644   if (!iter)
  4645     return nullptr;
  4647   RootedId nameid(cx);
  4648   if (!JS_NextProperty(cx, iter, nameid.address()))
  4649     return nullptr;
  4650   if (JSID_IS_VOID(nameid)) {
  4651     JS_ReportError(cx, "struct field descriptors require a valid name and type");
  4652     return nullptr;
  4655   if (!JSID_IS_STRING(nameid)) {
  4656     JS_ReportError(cx, "struct field descriptors require a valid name and type");
  4657     return nullptr;
  4660   // make sure we have one, and only one, property
  4661   jsid id;
  4662   if (!JS_NextProperty(cx, iter, &id))
  4663     return nullptr;
  4664   if (!JSID_IS_VOID(id)) {
  4665     JS_ReportError(cx, "struct field descriptors must contain one property");
  4666     return nullptr;
  4669   RootedValue propVal(cx);
  4670   if (!JS_GetPropertyById(cx, obj, nameid, &propVal))
  4671     return nullptr;
  4673   if (propVal.isPrimitive() || !CType::IsCType(&propVal.toObject())) {
  4674     JS_ReportError(cx, "struct field descriptors require a valid name and type");
  4675     return nullptr;
  4678   // Undefined size or zero size struct members are illegal.
  4679   // (Zero-size arrays are legal as struct members in C++, but libffi will
  4680   // choke on a zero-size struct, so we disallow them.)
  4681   *typeObj = &propVal.toObject();
  4682   size_t size;
  4683   if (!CType::GetSafeSize(*typeObj, &size) || size == 0) {
  4684     JS_ReportError(cx, "struct field types must have defined and nonzero size");
  4685     return nullptr;
  4688   return JSID_TO_FLAT_STRING(nameid);
  4691 // For a struct field with 'name' and 'type', add an element of the form
  4692 // { name : type }.
  4693 static bool
  4694 AddFieldToArray(JSContext* cx,
  4695                 jsval* element,
  4696                 JSFlatString* name_,
  4697                 JSObject* typeObj_)
  4699   RootedObject typeObj(cx, typeObj_);
  4700   Rooted<JSFlatString*> name(cx, name_);
  4701   RootedObject fieldObj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
  4702   if (!fieldObj)
  4703     return false;
  4705   *element = OBJECT_TO_JSVAL(fieldObj);
  4707   if (!JS_DefineUCProperty(cx, fieldObj,
  4708          name->chars(), name->length(),
  4709          OBJECT_TO_JSVAL(typeObj), nullptr, nullptr,
  4710          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
  4711     return false;
  4713   return JS_FreezeObject(cx, fieldObj);
  4716 bool
  4717 StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
  4719   CallArgs args = CallArgsFromVp(argc, vp);
  4721   // Construct and return a new StructType object.
  4722   if (args.length() < 1 || args.length() > 2) {
  4723     JS_ReportError(cx, "StructType takes one or two arguments");
  4724     return false;
  4727   jsval name = args[0];
  4728   if (!name.isString()) {
  4729     JS_ReportError(cx, "first argument must be a string");
  4730     return false;
  4733   // Get ctypes.StructType.prototype from the ctypes.StructType constructor.
  4734   RootedObject typeProto(cx, CType::GetProtoFromCtor(&args.callee(), SLOT_STRUCTPROTO));
  4736   // Create a simple StructType with no defined fields. The result will be
  4737   // non-instantiable as CData, will have no 'prototype' property, and will
  4738   // have undefined size and alignment and no ffi_type.
  4739   RootedObject result(cx, CType::Create(cx, typeProto, NullPtr(), TYPE_struct,
  4740                                         JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, nullptr));
  4741   if (!result)
  4742     return false;
  4744   if (args.length() == 2) {
  4745     RootedObject arr(cx, JSVAL_IS_PRIMITIVE(args[1]) ? nullptr : &args[1].toObject());
  4746     if (!arr || !JS_IsArrayObject(cx, arr)) {
  4747       JS_ReportError(cx, "second argument must be an array");
  4748       return false;
  4751     // Define the struct fields.
  4752     if (!DefineInternal(cx, result, arr))
  4753       return false;
  4756   args.rval().setObject(*result);
  4757   return true;
  4760 static void
  4761 PostBarrierCallback(JSTracer *trc, JSString *key, void *data)
  4763     typedef HashMap<JSFlatString*,
  4764                     UnbarrieredFieldInfo,
  4765                     FieldHashPolicy,
  4766                     SystemAllocPolicy> UnbarrieredFieldInfoHash;
  4768     UnbarrieredFieldInfoHash *table = reinterpret_cast<UnbarrieredFieldInfoHash*>(data);
  4769     JSString *prior = key;
  4770     JS_CallStringTracer(trc, &key, "CType fieldName");
  4771     table->rekeyIfMoved(JS_ASSERT_STRING_IS_FLAT(prior), JS_ASSERT_STRING_IS_FLAT(key));
  4774 bool
  4775 StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsObj_)
  4777   RootedObject typeObj(cx, typeObj_);
  4778   RootedObject fieldsObj(cx, fieldsObj_);
  4780   uint32_t len;
  4781   ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len));
  4783   // Get the common prototype for CData objects of this type from
  4784   // ctypes.CType.prototype.
  4785   RootedObject dataProto(cx, CType::GetProtoFromType(cx, typeObj, SLOT_STRUCTDATAPROTO));
  4786   if (!dataProto)
  4787     return false;
  4789   // Set up the 'prototype' and 'prototype.constructor' properties.
  4790   // The prototype will reflect the struct fields as properties on CData objects
  4791   // created from this type.
  4792   RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, NullPtr()));
  4793   if (!prototype)
  4794     return false;
  4796   if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
  4797                          JSPROP_READONLY | JSPROP_PERMANENT))
  4798     return false;
  4800   // Create a FieldInfoHash to stash on the type object, and an array to root
  4801   // its constituents. (We cannot simply stash the hash in a reserved slot now
  4802   // to get GC safety for free, since if anything in this function fails we
  4803   // do not want to mutate 'typeObj'.)
  4804   AutoPtr<FieldInfoHash> fields(cx->new_<FieldInfoHash>());
  4805   if (!fields || !fields->init(len)) {
  4806     JS_ReportOutOfMemory(cx);
  4807     return false;
  4809   JS::AutoValueVector fieldRoots(cx);
  4810   if (!fieldRoots.resize(len)) {
  4811     JS_ReportOutOfMemory(cx);
  4812     return false;
  4815   // Process the field types.
  4816   size_t structSize, structAlign;
  4817   if (len != 0) {
  4818     structSize = 0;
  4819     structAlign = 0;
  4821     for (uint32_t i = 0; i < len; ++i) {
  4822       RootedValue item(cx);
  4823       if (!JS_GetElement(cx, fieldsObj, i, &item))
  4824         return false;
  4826       RootedObject fieldType(cx, nullptr);
  4827       Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, fieldType.address()));
  4828       if (!name)
  4829         return false;
  4830       fieldRoots[i] = JS::ObjectValue(*fieldType);
  4832       // Make sure each field name is unique
  4833       FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
  4834       if (entryPtr) {
  4835         JS_ReportError(cx, "struct fields must have unique names");
  4836         return false;
  4839       // Add the field to the StructType's 'prototype' property.
  4840       if (!JS_DefineUCProperty(cx, prototype,
  4841              name->chars(), name->length(), JSVAL_VOID,
  4842              StructType::FieldGetter, StructType::FieldSetter,
  4843              JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT))
  4844         return false;
  4846       size_t fieldSize = CType::GetSize(fieldType);
  4847       size_t fieldAlign = CType::GetAlignment(fieldType);
  4848       size_t fieldOffset = Align(structSize, fieldAlign);
  4849       // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
  4850       // be zero, we can safely check fieldOffset + fieldSize without first
  4851       // checking fieldOffset for overflow.
  4852       if (fieldOffset + fieldSize < structSize) {
  4853         JS_ReportError(cx, "size overflow");
  4854         return false;
  4857       // Add field name to the hash
  4858       FieldInfo info;
  4859       info.mType = fieldType;
  4860       info.mIndex = i;
  4861       info.mOffset = fieldOffset;
  4862       ASSERT_OK(fields->add(entryPtr, name, info));
  4863       JS_StoreStringPostBarrierCallback(cx, PostBarrierCallback, name, fields.get());
  4865       structSize = fieldOffset + fieldSize;
  4867       if (fieldAlign > structAlign)
  4868         structAlign = fieldAlign;
  4871     // Pad the struct tail according to struct alignment.
  4872     size_t structTail = Align(structSize, structAlign);
  4873     if (structTail < structSize) {
  4874       JS_ReportError(cx, "size overflow");
  4875       return false;
  4877     structSize = structTail;
  4879   } else {
  4880     // Empty structs are illegal in C, but are legal and have a size of
  4881     // 1 byte in C++. We're going to allow them, and trick libffi into
  4882     // believing this by adding a char member. The resulting struct will have
  4883     // no getters or setters, and will be initialized to zero.
  4884     structSize = 1;
  4885     structAlign = 1;
  4888   RootedValue sizeVal(cx);
  4889   if (!SizeTojsval(cx, structSize, sizeVal.address()))
  4890     return false;
  4892   JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PRIVATE_TO_JSVAL(fields.forget()));
  4894   JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
  4895   JS_SetReservedSlot(typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign));
  4896   //if (!JS_FreezeObject(cx, prototype)0 // XXX fixme - see bug 541212!
  4897   //  return false;
  4898   JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
  4899   return true;
  4902 ffi_type*
  4903 StructType::BuildFFIType(JSContext* cx, JSObject* obj)
  4905   JS_ASSERT(CType::IsCType(obj));
  4906   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  4907   JS_ASSERT(CType::IsSizeDefined(obj));
  4909   const FieldInfoHash* fields = GetFieldInfo(obj);
  4910   size_t len = fields->count();
  4912   size_t structSize = CType::GetSize(obj);
  4913   size_t structAlign = CType::GetAlignment(obj);
  4915   AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
  4916   if (!ffiType) {
  4917     JS_ReportOutOfMemory(cx);
  4918     return nullptr;
  4920   ffiType->type = FFI_TYPE_STRUCT;
  4922   AutoPtr<ffi_type*> elements;
  4923   if (len != 0) {
  4924     elements = cx->pod_malloc<ffi_type*>(len + 1);
  4925     if (!elements) {
  4926       JS_ReportOutOfMemory(cx);
  4927       return nullptr;
  4929     elements[len] = nullptr;
  4931     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  4932       const FieldInfoHash::Entry& entry = r.front();
  4933       ffi_type* fieldType = CType::GetFFIType(cx, entry.value().mType);
  4934       if (!fieldType)
  4935         return nullptr;
  4936       elements[entry.value().mIndex] = fieldType;
  4939   } else {
  4940     // Represent an empty struct as having a size of 1 byte, just like C++.
  4941     JS_ASSERT(structSize == 1);
  4942     JS_ASSERT(structAlign == 1);
  4943     elements = cx->pod_malloc<ffi_type*>(2);
  4944     if (!elements) {
  4945       JS_ReportOutOfMemory(cx);
  4946       return nullptr;
  4948     elements[0] = &ffi_type_uint8;
  4949     elements[1] = nullptr;
  4952   ffiType->elements = elements.get();
  4954 #ifdef DEBUG
  4955   // Perform a sanity check: the result of our struct size and alignment
  4956   // calculations should match libffi's. We force it to do this calculation
  4957   // by calling ffi_prep_cif.
  4958   ffi_cif cif;
  4959   ffiType->size = 0;
  4960   ffiType->alignment = 0;
  4961   ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), nullptr);
  4962   JS_ASSERT(status == FFI_OK);
  4963   JS_ASSERT(structSize == ffiType->size);
  4964   JS_ASSERT(structAlign == ffiType->alignment);
  4965 #else
  4966   // Fill in the ffi_type's size and align fields. This makes libffi treat the
  4967   // type as initialized; it will not recompute the values. (We assume
  4968   // everything agrees; if it doesn't, we really want to know about it, which
  4969   // is the purpose of the above debug-only check.)
  4970   ffiType->size = structSize;
  4971   ffiType->alignment = structAlign;
  4972 #endif
  4974   elements.forget();
  4975   return ffiType.forget();
  4978 bool
  4979 StructType::Define(JSContext* cx, unsigned argc, jsval* vp)
  4981   CallArgs args = CallArgsFromVp(argc, vp);
  4982   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  4983   if (!obj)
  4984     return false;
  4985   if (!CType::IsCType(obj) ||
  4986       CType::GetTypeCode(obj) != TYPE_struct) {
  4987     JS_ReportError(cx, "not a StructType");
  4988     return false;
  4991   if (CType::IsSizeDefined(obj)) {
  4992     JS_ReportError(cx, "StructType has already been defined");
  4993     return false;
  4996   if (args.length() != 1) {
  4997     JS_ReportError(cx, "define takes one argument");
  4998     return false;
  5001   jsval arg = args[0];
  5002   if (JSVAL_IS_PRIMITIVE(arg)) {
  5003     JS_ReportError(cx, "argument must be an array");
  5004     return false;
  5006   RootedObject arr(cx, JSVAL_TO_OBJECT(arg));
  5007   if (!JS_IsArrayObject(cx, arr)) {
  5008     JS_ReportError(cx, "argument must be an array");
  5009     return false;
  5012   return DefineInternal(cx, obj, arr);
  5015 bool
  5016 StructType::ConstructData(JSContext* cx,
  5017                           HandleObject obj,
  5018                           const CallArgs& args)
  5020   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_struct) {
  5021     JS_ReportError(cx, "not a StructType");
  5022     return false;
  5025   if (!CType::IsSizeDefined(obj)) {
  5026     JS_ReportError(cx, "cannot construct an opaque StructType");
  5027     return false;
  5030   JSObject* result = CData::Create(cx, obj, NullPtr(), nullptr, true);
  5031   if (!result)
  5032     return false;
  5034   args.rval().setObject(*result);
  5036   if (args.length() == 0)
  5037     return true;
  5039   char* buffer = static_cast<char*>(CData::GetData(result));
  5040   const FieldInfoHash* fields = GetFieldInfo(obj);
  5042   if (args.length() == 1) {
  5043     // There are two possible interpretations of the argument:
  5044     // 1) It may be an object '{ ... }' with properties representing the
  5045     //    struct fields intended to ExplicitConvert wholesale to our StructType.
  5046     // 2) If the struct contains one field, the arg may be intended to
  5047     //    ImplicitConvert directly to that arg's CType.
  5048     // Thankfully, the conditions for these two possibilities to succeed
  5049     // are mutually exclusive, so we can pick the right one.
  5051     // Try option 1) first.
  5052     if (ExplicitConvert(cx, args[0], obj, buffer))
  5053       return true;
  5055     if (fields->count() != 1)
  5056       return false;
  5058     // If ExplicitConvert failed, and there is no pending exception, then assume
  5059     // hard failure (out of memory, or some other similarly serious condition).
  5060     if (!JS_IsExceptionPending(cx))
  5061       return false;
  5063     // Otherwise, assume soft failure, and clear the pending exception so that we
  5064     // can throw a different one as required.
  5065     JS_ClearPendingException(cx);
  5067     // Fall through to try option 2).
  5070   // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'.
  5071   // ImplicitConvert each field.
  5072   if (args.length() == fields->count()) {
  5073     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  5074       const FieldInfo& field = r.front().value();
  5075       STATIC_ASSUME(field.mIndex < fields->count());  /* Quantified invariant */
  5076       if (!ImplicitConvert(cx, args[field.mIndex], field.mType,
  5077              buffer + field.mOffset,
  5078              false, nullptr))
  5079         return false;
  5082     return true;
  5085   JS_ReportError(cx, "constructor takes 0, 1, or %u arguments",
  5086     fields->count());
  5087   return false;
  5090 const FieldInfoHash*
  5091 StructType::GetFieldInfo(JSObject* obj)
  5093   JS_ASSERT(CType::IsCType(obj));
  5094   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  5096   jsval slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
  5097   JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
  5099   return static_cast<const FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
  5102 const FieldInfo*
  5103 StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
  5105   JS_ASSERT(CType::IsCType(obj));
  5106   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  5108   FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name);
  5109   if (ptr)
  5110     return &ptr->value();
  5112   JSAutoByteString bytes(cx, name);
  5113   if (!bytes)
  5114     return nullptr;
  5116   JS_ReportError(cx, "%s does not name a field", bytes.ptr());
  5117   return nullptr;
  5120 JSObject*
  5121 StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
  5123   JS_ASSERT(CType::IsCType(obj));
  5124   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
  5125   JS_ASSERT(CType::IsSizeDefined(obj));
  5127   const FieldInfoHash* fields = GetFieldInfo(obj);
  5128   size_t len = fields->count();
  5130   // Prepare a new array for the 'fields' property of the StructType.
  5131   JS::AutoValueVector fieldsVec(cx);
  5132   if (!fieldsVec.resize(len))
  5133     return nullptr;
  5135   for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
  5136     const FieldInfoHash::Entry& entry = r.front();
  5137     // Add the field descriptor to the array.
  5138     if (!AddFieldToArray(cx, &fieldsVec[entry.value().mIndex],
  5139                          entry.key(), entry.value().mType))
  5140       return nullptr;
  5143   RootedObject fieldsProp(cx, JS_NewArrayObject(cx, fieldsVec));
  5144   if (!fieldsProp)
  5145     return nullptr;
  5147   // Seal the fields array.
  5148   if (!JS_FreezeObject(cx, fieldsProp))
  5149     return nullptr;
  5151   return fieldsProp;
  5154 /* static */ bool
  5155 StructType::IsStruct(HandleValue v)
  5157   if (!v.isObject())
  5158     return false;
  5159   JSObject* obj = &v.toObject();
  5160   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_struct;
  5163 bool
  5164 StructType::FieldsArrayGetter(JSContext* cx, JS::CallArgs args)
  5166   RootedObject obj(cx, &args.thisv().toObject());
  5168   args.rval().set(JS_GetReservedSlot(obj, SLOT_FIELDS));
  5170   if (!CType::IsSizeDefined(obj)) {
  5171     MOZ_ASSERT(args.rval().isUndefined());
  5172     return true;
  5175   if (args.rval().isUndefined()) {
  5176     // Build the 'fields' array lazily.
  5177     JSObject* fields = BuildFieldsArray(cx, obj);
  5178     if (!fields)
  5179       return false;
  5180     JS_SetReservedSlot(obj, SLOT_FIELDS, OBJECT_TO_JSVAL(fields));
  5182     args.rval().setObject(*fields);
  5185   MOZ_ASSERT(args.rval().isObject());
  5186   MOZ_ASSERT(JS_IsArrayObject(cx, args.rval()));
  5187   return true;
  5190 bool
  5191 StructType::FieldGetter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp)
  5193   if (!CData::IsCData(obj)) {
  5194     JS_ReportError(cx, "not a CData");
  5195     return false;
  5198   JSObject* typeObj = CData::GetCType(obj);
  5199   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  5200     JS_ReportError(cx, "not a StructType");
  5201     return false;
  5204   const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
  5205   if (!field)
  5206     return false;
  5208   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  5209   RootedObject fieldType(cx, field->mType);
  5210   return ConvertToJS(cx, fieldType, obj, data, false, false, vp.address());
  5213 bool
  5214 StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
  5216   if (!CData::IsCData(obj)) {
  5217     JS_ReportError(cx, "not a CData");
  5218     return false;
  5221   JSObject* typeObj = CData::GetCType(obj);
  5222   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  5223     JS_ReportError(cx, "not a StructType");
  5224     return false;
  5227   const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
  5228   if (!field)
  5229     return false;
  5231   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  5232   return ImplicitConvert(cx, vp, field->mType, data, false, nullptr);
  5235 bool
  5236 StructType::AddressOfField(JSContext* cx, unsigned argc, jsval* vp)
  5238   CallArgs args = CallArgsFromVp(argc, vp);
  5239   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  5240   if (!obj)
  5241     return false;
  5242   if (!CData::IsCData(obj)) {
  5243     JS_ReportError(cx, "not a CData");
  5244     return false;
  5247   JSObject* typeObj = CData::GetCType(obj);
  5248   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
  5249     JS_ReportError(cx, "not a StructType");
  5250     return false;
  5253   if (args.length() != 1) {
  5254     JS_ReportError(cx, "addressOfField takes one argument");
  5255     return false;
  5258   JSFlatString *str = JS_FlattenString(cx, args[0].toString());
  5259   if (!str)
  5260     return false;
  5262   const FieldInfo* field = LookupField(cx, typeObj, str);
  5263   if (!field)
  5264     return false;
  5266   RootedObject baseType(cx, field->mType);
  5267   RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
  5268   if (!pointerType)
  5269     return false;
  5271   // Create a PointerType CData object containing null.
  5272   JSObject* result = CData::Create(cx, pointerType, NullPtr(), nullptr, true);
  5273   if (!result)
  5274     return false;
  5276   args.rval().setObject(*result);
  5278   // Manually set the pointer inside the object, so we skip the conversion step.
  5279   void** data = static_cast<void**>(CData::GetData(result));
  5280   *data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
  5281   return true;
  5284 /*******************************************************************************
  5285 ** FunctionType implementation
  5286 *******************************************************************************/
  5288 // Helper class for handling allocation of function arguments.
  5289 struct AutoValue
  5291   AutoValue() : mData(nullptr) { }
  5293   ~AutoValue()
  5295     js_free(mData);
  5298   bool SizeToType(JSContext* cx, JSObject* type)
  5300     // Allocate a minimum of sizeof(ffi_arg) to handle small integers.
  5301     size_t size = Align(CType::GetSize(type), sizeof(ffi_arg));
  5302     mData = js_malloc(size);
  5303     if (mData)
  5304       memset(mData, 0, size);
  5305     return mData != nullptr;
  5308   void* mData;
  5309 };
  5311 static bool
  5312 GetABI(JSContext* cx, jsval abiType, ffi_abi* result)
  5314   if (JSVAL_IS_PRIMITIVE(abiType))
  5315     return false;
  5317   ABICode abi = GetABICode(JSVAL_TO_OBJECT(abiType));
  5319   // determine the ABI from the subset of those available on the
  5320   // given platform. ABI_DEFAULT specifies the default
  5321   // C calling convention (cdecl) on each platform.
  5322   switch (abi) {
  5323   case ABI_DEFAULT:
  5324     *result = FFI_DEFAULT_ABI;
  5325     return true;
  5326   case ABI_STDCALL:
  5327   case ABI_WINAPI:
  5328 #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
  5329     *result = FFI_STDCALL;
  5330     return true;
  5331 #elif (defined(_WIN64))
  5332     // We'd like the same code to work across Win32 and Win64, so stdcall_api
  5333     // and winapi_abi become aliases to the lone Win64 ABI.
  5334     *result = FFI_WIN64;
  5335     return true;
  5336 #endif
  5337   case INVALID_ABI:
  5338     break;
  5340   return false;
  5343 static JSObject*
  5344 PrepareType(JSContext* cx, jsval type)
  5346   if (JSVAL_IS_PRIMITIVE(type) ||
  5347       !CType::IsCType(JSVAL_TO_OBJECT(type))) {
  5348     JS_ReportError(cx, "not a ctypes type");
  5349     return nullptr;
  5352   JSObject* result = JSVAL_TO_OBJECT(type);
  5353   TypeCode typeCode = CType::GetTypeCode(result);
  5355   if (typeCode == TYPE_array) {
  5356     // convert array argument types to pointers, just like C.
  5357     // ImplicitConvert will do the same, when passing an array as data.
  5358     RootedObject baseType(cx, ArrayType::GetBaseType(result));
  5359     result = PointerType::CreateInternal(cx, baseType);
  5360     if (!result)
  5361       return nullptr;
  5363   } else if (typeCode == TYPE_void_t || typeCode == TYPE_function) {
  5364     // disallow void or function argument types
  5365     JS_ReportError(cx, "Cannot have void or function argument type");
  5366     return nullptr;
  5369   if (!CType::IsSizeDefined(result)) {
  5370     JS_ReportError(cx, "Argument type must have defined size");
  5371     return nullptr;
  5374   // libffi cannot pass types of zero size by value.
  5375   JS_ASSERT(CType::GetSize(result) != 0);
  5377   return result;
  5380 static JSObject*
  5381 PrepareReturnType(JSContext* cx, jsval type)
  5383   if (JSVAL_IS_PRIMITIVE(type) ||
  5384       !CType::IsCType(JSVAL_TO_OBJECT(type))) {
  5385     JS_ReportError(cx, "not a ctypes type");
  5386     return nullptr;
  5389   JSObject* result = JSVAL_TO_OBJECT(type);
  5390   TypeCode typeCode = CType::GetTypeCode(result);
  5392   // Arrays and functions can never be return types.
  5393   if (typeCode == TYPE_array || typeCode == TYPE_function) {
  5394     JS_ReportError(cx, "Return type cannot be an array or function");
  5395     return nullptr;
  5398   if (typeCode != TYPE_void_t && !CType::IsSizeDefined(result)) {
  5399     JS_ReportError(cx, "Return type must have defined size");
  5400     return nullptr;
  5403   // libffi cannot pass types of zero size by value.
  5404   JS_ASSERT(typeCode == TYPE_void_t || CType::GetSize(result) != 0);
  5406   return result;
  5409 static MOZ_ALWAYS_INLINE bool
  5410 IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
  5412   *isEllipsis = false;
  5413   if (!JSVAL_IS_STRING(v))
  5414     return true;
  5415   JSString* str = JSVAL_TO_STRING(v);
  5416   if (str->length() != 3)
  5417     return true;
  5418   const jschar* chars = str->getChars(cx);
  5419   if (!chars)
  5420     return false;
  5421   jschar dot = '.';
  5422   *isEllipsis = (chars[0] == dot &&
  5423                  chars[1] == dot &&
  5424                  chars[2] == dot);
  5425   return true;
  5428 static bool
  5429 PrepareCIF(JSContext* cx,
  5430            FunctionInfo* fninfo)
  5432   ffi_abi abi;
  5433   if (!GetABI(cx, OBJECT_TO_JSVAL(fninfo->mABI), &abi)) {
  5434     JS_ReportError(cx, "Invalid ABI specification");
  5435     return false;
  5438   ffi_type* rtype = CType::GetFFIType(cx, fninfo->mReturnType);
  5439   if (!rtype)
  5440     return false;
  5442   ffi_status status =
  5443     ffi_prep_cif(&fninfo->mCIF,
  5444                  abi,
  5445                  fninfo->mFFITypes.length(),
  5446                  rtype,
  5447                  fninfo->mFFITypes.begin());
  5449   switch (status) {
  5450   case FFI_OK:
  5451     return true;
  5452   case FFI_BAD_ABI:
  5453     JS_ReportError(cx, "Invalid ABI specification");
  5454     return false;
  5455   case FFI_BAD_TYPEDEF:
  5456     JS_ReportError(cx, "Invalid type specification");
  5457     return false;
  5458   default:
  5459     JS_ReportError(cx, "Unknown libffi error");
  5460     return false;
  5464 void
  5465 FunctionType::BuildSymbolName(JSString* name,
  5466                               JSObject* typeObj,
  5467                               AutoCString& result)
  5469   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
  5471   switch (GetABICode(fninfo->mABI)) {
  5472   case ABI_DEFAULT:
  5473   case ABI_WINAPI:
  5474     // For cdecl or WINAPI functions, no mangling is necessary.
  5475     AppendString(result, name);
  5476     break;
  5478   case ABI_STDCALL: {
  5479 #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
  5480     // On WIN32, stdcall functions look like:
  5481     //   _foo@40
  5482     // where 'foo' is the function name, and '40' is the aligned size of the
  5483     // arguments.
  5484     AppendString(result, "_");
  5485     AppendString(result, name);
  5486     AppendString(result, "@");
  5488     // Compute the suffix by aligning each argument to sizeof(ffi_arg).
  5489     size_t size = 0;
  5490     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
  5491       JSObject* argType = fninfo->mArgTypes[i];
  5492       size += Align(CType::GetSize(argType), sizeof(ffi_arg));
  5495     IntegerToString(size, 10, result);
  5496 #elif defined(_WIN64)
  5497     // On Win64, stdcall is an alias to the default ABI for compatibility, so no
  5498     // mangling is done.
  5499     AppendString(result, name);
  5500 #endif
  5501     break;
  5504   case INVALID_ABI:
  5505     MOZ_ASSUME_UNREACHABLE("invalid abi");
  5509 static FunctionInfo*
  5510 NewFunctionInfo(JSContext* cx,
  5511                 jsval abiType,
  5512                 jsval returnType,
  5513                 jsval* argTypes,
  5514                 unsigned argLength)
  5516   AutoPtr<FunctionInfo> fninfo(cx->new_<FunctionInfo>());
  5517   if (!fninfo) {
  5518     JS_ReportOutOfMemory(cx);
  5519     return nullptr;
  5522   ffi_abi abi;
  5523   if (!GetABI(cx, abiType, &abi)) {
  5524     JS_ReportError(cx, "Invalid ABI specification");
  5525     return nullptr;
  5527   fninfo->mABI = JSVAL_TO_OBJECT(abiType);
  5529   // prepare the result type
  5530   fninfo->mReturnType = PrepareReturnType(cx, returnType);
  5531   if (!fninfo->mReturnType)
  5532     return nullptr;
  5534   // prepare the argument types
  5535   if (!fninfo->mArgTypes.reserve(argLength) ||
  5536       !fninfo->mFFITypes.reserve(argLength)) {
  5537     JS_ReportOutOfMemory(cx);
  5538     return nullptr;
  5541   fninfo->mIsVariadic = false;
  5543   for (uint32_t i = 0; i < argLength; ++i) {
  5544     bool isEllipsis;
  5545     if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
  5546       return nullptr;
  5547     if (isEllipsis) {
  5548       fninfo->mIsVariadic = true;
  5549       if (i < 1) {
  5550         JS_ReportError(cx, "\"...\" may not be the first and only parameter "
  5551                        "type of a variadic function declaration");
  5552         return nullptr;
  5554       if (i < argLength - 1) {
  5555         JS_ReportError(cx, "\"...\" must be the last parameter type of a "
  5556                        "variadic function declaration");
  5557         return nullptr;
  5559       if (GetABICode(fninfo->mABI) != ABI_DEFAULT) {
  5560         JS_ReportError(cx, "Variadic functions must use the __cdecl calling "
  5561                        "convention");
  5562         return nullptr;
  5564       break;
  5567     JSObject* argType = PrepareType(cx, argTypes[i]);
  5568     if (!argType)
  5569       return nullptr;
  5571     ffi_type* ffiType = CType::GetFFIType(cx, argType);
  5572     if (!ffiType)
  5573       return nullptr;
  5575     fninfo->mArgTypes.infallibleAppend(argType);
  5576     fninfo->mFFITypes.infallibleAppend(ffiType);
  5579   if (fninfo->mIsVariadic)
  5580     // wait to PrepareCIF until function is called
  5581     return fninfo.forget();
  5583   if (!PrepareCIF(cx, fninfo.get()))
  5584     return nullptr;
  5586   return fninfo.forget();
  5589 bool
  5590 FunctionType::Create(JSContext* cx, unsigned argc, jsval* vp)
  5592   // Construct and return a new FunctionType object.
  5593   CallArgs args = CallArgsFromVp(argc, vp);
  5594   if (args.length() < 2 || args.length() > 3) {
  5595     JS_ReportError(cx, "FunctionType takes two or three arguments");
  5596     return false;
  5599   AutoValueVector argTypes(cx);
  5600   RootedObject arrayObj(cx, nullptr);
  5602   if (args.length() == 3) {
  5603     // Prepare an array of jsvals for the arguments.
  5604     if (!JSVAL_IS_PRIMITIVE(args[2]))
  5605       arrayObj = &args[2].toObject();
  5606     if (!arrayObj || !JS_IsArrayObject(cx, arrayObj)) {
  5607       JS_ReportError(cx, "third argument must be an array");
  5608       return false;
  5611     uint32_t len;
  5612     ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len));
  5614     if (!argTypes.resize(len)) {
  5615       JS_ReportOutOfMemory(cx);
  5616       return false;
  5620   // Pull out the argument types from the array, if any.
  5621   JS_ASSERT_IF(argTypes.length(), arrayObj);
  5622   for (uint32_t i = 0; i < argTypes.length(); ++i) {
  5623     if (!JS_GetElement(cx, arrayObj, i, argTypes.handleAt(i)))
  5624       return false;
  5627   JSObject* result = CreateInternal(cx, args[0], args[1],
  5628       argTypes.begin(), argTypes.length());
  5629   if (!result)
  5630     return false;
  5632   args.rval().setObject(*result);
  5633   return true;
  5636 JSObject*
  5637 FunctionType::CreateInternal(JSContext* cx,
  5638                              jsval abi,
  5639                              jsval rtype,
  5640                              jsval* argtypes,
  5641                              unsigned arglen)
  5643   // Determine and check the types, and prepare the function CIF.
  5644   AutoPtr<FunctionInfo> fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen));
  5645   if (!fninfo)
  5646     return nullptr;
  5648   // Get ctypes.FunctionType.prototype and the common prototype for CData objects
  5649   // of this type, from ctypes.CType.prototype.
  5650   RootedObject typeProto(cx, CType::GetProtoFromType(cx, fninfo->mReturnType,
  5651                                                      SLOT_FUNCTIONPROTO));
  5652   if (!typeProto)
  5653     return nullptr;
  5654   RootedObject dataProto(cx, CType::GetProtoFromType(cx, fninfo->mReturnType,
  5655                                                      SLOT_FUNCTIONDATAPROTO));
  5656   if (!dataProto)
  5657     return nullptr;
  5659   // Create a new CType object with the common properties and slots.
  5660   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_function,
  5661                         nullptr, JSVAL_VOID, JSVAL_VOID, nullptr);
  5662   if (!typeObj)
  5663     return nullptr;
  5665   // Stash the FunctionInfo in a reserved slot.
  5666   JS_SetReservedSlot(typeObj, SLOT_FNINFO, PRIVATE_TO_JSVAL(fninfo.forget()));
  5668   return typeObj;
  5671 // Construct a function pointer to a JS function (see CClosure::Create()).
  5672 // Regular function pointers are constructed directly in
  5673 // PointerType::ConstructData().
  5674 bool
  5675 FunctionType::ConstructData(JSContext* cx,
  5676                             HandleObject typeObj,
  5677                             HandleObject dataObj,
  5678                             HandleObject fnObj,
  5679                             HandleObject thisObj,
  5680                             jsval errVal)
  5682   JS_ASSERT(CType::GetTypeCode(typeObj) == TYPE_function);
  5684   PRFuncPtr* data = static_cast<PRFuncPtr*>(CData::GetData(dataObj));
  5686   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  5687   if (fninfo->mIsVariadic) {
  5688     JS_ReportError(cx, "Can't declare a variadic callback function");
  5689     return false;
  5691   if (GetABICode(fninfo->mABI) == ABI_WINAPI) {
  5692     JS_ReportError(cx, "Can't declare a ctypes.winapi_abi callback function, "
  5693                    "use ctypes.stdcall_abi instead");
  5694     return false;
  5697   RootedObject closureObj(cx, CClosure::Create(cx, typeObj, fnObj, thisObj, errVal, data));
  5698   if (!closureObj)
  5699     return false;
  5701   // Set the closure object as the referent of the new CData object.
  5702   JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(closureObj));
  5704   // Seal the CData object, to prevent modification of the function pointer.
  5705   // This permanently associates this object with the closure, and avoids
  5706   // having to do things like reset SLOT_REFERENT when someone tries to
  5707   // change the pointer value.
  5708   // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
  5709   // could be called on a frozen object.
  5710   return JS_FreezeObject(cx, dataObj);
  5713 typedef Array<AutoValue, 16> AutoValueAutoArray;
  5715 static bool
  5716 ConvertArgument(JSContext* cx,
  5717                 HandleValue arg,
  5718                 JSObject* type,
  5719                 AutoValue* value,
  5720                 AutoValueAutoArray* strings)
  5722   if (!value->SizeToType(cx, type)) {
  5723     JS_ReportAllocationOverflow(cx);
  5724     return false;
  5727   bool freePointer = false;
  5728   if (!ImplicitConvert(cx, arg, type, value->mData, true, &freePointer))
  5729     return false;
  5731   if (freePointer) {
  5732     // ImplicitConvert converted a string for us, which we have to free.
  5733     // Keep track of it.
  5734     if (!strings->growBy(1)) {
  5735       JS_ReportOutOfMemory(cx);
  5736       return false;
  5738     strings->back().mData = *static_cast<char**>(value->mData);
  5741   return true;
  5744 bool
  5745 FunctionType::Call(JSContext* cx,
  5746                    unsigned argc,
  5747                    jsval* vp)
  5749   CallArgs args = CallArgsFromVp(argc, vp);
  5750   // get the callee object...
  5751   RootedObject obj(cx, &args.callee());
  5752   if (!CData::IsCData(obj)) {
  5753     JS_ReportError(cx, "not a CData");
  5754     return false;
  5757   RootedObject typeObj(cx, CData::GetCType(obj));
  5758   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
  5759     JS_ReportError(cx, "not a FunctionType.ptr");
  5760     return false;
  5763   typeObj = PointerType::GetBaseType(typeObj);
  5764   if (CType::GetTypeCode(typeObj) != TYPE_function) {
  5765     JS_ReportError(cx, "not a FunctionType.ptr");
  5766     return false;
  5769   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
  5770   uint32_t argcFixed = fninfo->mArgTypes.length();
  5772   if ((!fninfo->mIsVariadic && args.length() != argcFixed) ||
  5773       (fninfo->mIsVariadic && args.length() < argcFixed)) {
  5774     JS_ReportError(cx, "Number of arguments does not match declaration");
  5775     return false;
  5778   // Check if we have a Library object. If we do, make sure it's open.
  5779   jsval slot = JS_GetReservedSlot(obj, SLOT_REFERENT);
  5780   if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
  5781     PRLibrary* library = Library::GetLibrary(&slot.toObject());
  5782     if (!library) {
  5783       JS_ReportError(cx, "library is not open");
  5784       return false;
  5788   // prepare the values for each argument
  5789   AutoValueAutoArray values;
  5790   AutoValueAutoArray strings;
  5791   if (!values.resize(args.length())) {
  5792     JS_ReportOutOfMemory(cx);
  5793     return false;
  5796   for (unsigned i = 0; i < argcFixed; ++i)
  5797     if (!ConvertArgument(cx, args[i], fninfo->mArgTypes[i], &values[i], &strings))
  5798       return false;
  5800   if (fninfo->mIsVariadic) {
  5801     if (!fninfo->mFFITypes.resize(args.length())) {
  5802       JS_ReportOutOfMemory(cx);
  5803       return false;
  5806     RootedObject obj(cx);  // Could reuse obj instead of declaring a second
  5807     RootedObject type(cx); // RootedObject, but readability would suffer.
  5809     for (uint32_t i = argcFixed; i < args.length(); ++i) {
  5810       if (JSVAL_IS_PRIMITIVE(args[i]) ||
  5811           !CData::IsCData(obj = &args[i].toObject())) {
  5812         // Since we know nothing about the CTypes of the ... arguments,
  5813         // they absolutely must be CData objects already.
  5814         JS_ReportError(cx, "argument %d of type %s is not a CData object",
  5815                        i, JS_GetTypeName(cx, JS_TypeOfValue(cx, args[i])));
  5816         return false;
  5818       if (!(type = CData::GetCType(obj)) ||
  5819           !(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) ||
  5820           // Relying on ImplicitConvert only for the limited purpose of
  5821           // converting one CType to another (e.g., T[] to T*).
  5822           !ConvertArgument(cx, args[i], type, &values[i], &strings) ||
  5823           !(fninfo->mFFITypes[i] = CType::GetFFIType(cx, type))) {
  5824         // These functions report their own errors.
  5825         return false;
  5828     if (!PrepareCIF(cx, fninfo))
  5829       return false;
  5832   // initialize a pointer to an appropriate location, for storing the result
  5833   AutoValue returnValue;
  5834   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
  5835   if (typeCode != TYPE_void_t &&
  5836       !returnValue.SizeToType(cx, fninfo->mReturnType)) {
  5837     JS_ReportAllocationOverflow(cx);
  5838     return false;
  5841   // Let the runtime callback know that we are about to call into C.
  5842   js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALL_BEGIN, js::CTYPES_CALL_END);
  5844   uintptr_t fn = *reinterpret_cast<uintptr_t*>(CData::GetData(obj));
  5846 #if defined(XP_WIN)
  5847   int32_t lastErrorStatus; // The status as defined by |GetLastError|
  5848   int32_t savedLastError = GetLastError();
  5849   SetLastError(0);
  5850 #endif //defined(XP_WIN)
  5851   int errnoStatus;         // The status as defined by |errno|
  5852   int savedErrno = errno;
  5853   errno = 0;
  5855   ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData,
  5856            reinterpret_cast<void**>(values.begin()));
  5858   // Save error value.
  5859   // We need to save it before leaving the scope of |suspend| as destructing
  5860   // |suspend| has the side-effect of clearing |GetLastError|
  5861   // (see bug 684017).
  5863   errnoStatus = errno;
  5864 #if defined(XP_WIN)
  5865   lastErrorStatus = GetLastError();
  5866   SetLastError(savedLastError);
  5867 #endif // defined(XP_WIN)
  5869   errno = savedErrno;
  5871   // We're no longer calling into C.
  5872   autoCallback.DoEndCallback();
  5874   // Store the error value for later consultation with |ctypes.getStatus|
  5875   JSObject *objCTypes = CType::GetGlobalCTypes(cx, typeObj);
  5876   if (!objCTypes)
  5877     return false;
  5879   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
  5880 #if defined(XP_WIN)
  5881   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
  5882 #endif // defined(XP_WIN)
  5884   // Small integer types get returned as a word-sized ffi_arg. Coerce it back
  5885   // into the correct size for ConvertToJS.
  5886   switch (typeCode) {
  5887 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  5888   case TYPE_##name:                                                            \
  5889     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
  5890       ffi_arg data = *static_cast<ffi_arg*>(returnValue.mData);                \
  5891       *static_cast<type*>(returnValue.mData) = static_cast<type>(data);        \
  5892     }                                                                          \
  5893     break;
  5894 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  5895 #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  5896 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  5897 #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  5898 #include "ctypes/typedefs.h"
  5899   default:
  5900     break;
  5903   // prepare a JS object from the result
  5904   RootedObject returnType(cx, fninfo->mReturnType);
  5905   return ConvertToJS(cx, returnType, NullPtr(), returnValue.mData, false, true, vp);
  5908 FunctionInfo*
  5909 FunctionType::GetFunctionInfo(JSObject* obj)
  5911   JS_ASSERT(CType::IsCType(obj));
  5912   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_function);
  5914   jsval slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
  5915   JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
  5917   return static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
  5920 bool
  5921 FunctionType::IsFunctionType(HandleValue v)
  5923   if (!v.isObject())
  5924     return false;
  5925   JSObject* obj = &v.toObject();
  5926   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_function;
  5929 bool
  5930 FunctionType::ArgTypesGetter(JSContext* cx, JS::CallArgs args)
  5932   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
  5934   args.rval().set(JS_GetReservedSlot(obj, SLOT_ARGS_T));
  5935   if (!args.rval().isUndefined())
  5936     return true;
  5938   FunctionInfo* fninfo = GetFunctionInfo(obj);
  5939   size_t len = fninfo->mArgTypes.length();
  5941   // Prepare a new array.
  5942   JS::Rooted<JSObject*> argTypes(cx);
  5944       JS::AutoValueVector vec(cx);
  5945       if (!vec.resize(len))
  5946         return false;
  5948       for (size_t i = 0; i < len; ++i)
  5949         vec[i] = JS::ObjectValue(*fninfo->mArgTypes[i]);
  5951       argTypes = JS_NewArrayObject(cx, vec);
  5952       if (!argTypes)
  5953         return false;
  5956   // Seal and cache it.
  5957   if (!JS_FreezeObject(cx, argTypes))
  5958     return false;
  5959   JS_SetReservedSlot(obj, SLOT_ARGS_T, JS::ObjectValue(*argTypes));
  5961   args.rval().setObject(*argTypes);
  5962   return true;
  5965 bool
  5966 FunctionType::ReturnTypeGetter(JSContext* cx, JS::CallArgs args)
  5968   // Get the returnType object from the FunctionInfo.
  5969   args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mReturnType);
  5970   return true;
  5973 bool
  5974 FunctionType::ABIGetter(JSContext* cx, JS::CallArgs args)
  5976   // Get the abi object from the FunctionInfo.
  5977   args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mABI);
  5978   return true;
  5981 bool
  5982 FunctionType::IsVariadicGetter(JSContext* cx, JS::CallArgs args)
  5984   args.rval().setBoolean(GetFunctionInfo(&args.thisv().toObject())->mIsVariadic);
  5985   return true;
  5988 /*******************************************************************************
  5989 ** CClosure implementation
  5990 *******************************************************************************/
  5992 JSObject*
  5993 CClosure::Create(JSContext* cx,
  5994                  HandleObject typeObj,
  5995                  HandleObject fnObj,
  5996                  HandleObject thisObj,
  5997                  jsval errVal_,
  5998                  PRFuncPtr* fnptr)
  6000   RootedValue errVal(cx, errVal_);
  6001   JS_ASSERT(fnObj);
  6003   RootedObject result(cx, JS_NewObject(cx, &sCClosureClass, NullPtr(), NullPtr()));
  6004   if (!result)
  6005     return nullptr;
  6007   // Get the FunctionInfo from the FunctionType.
  6008   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  6009   JS_ASSERT(!fninfo->mIsVariadic);
  6010   JS_ASSERT(GetABICode(fninfo->mABI) != ABI_WINAPI);
  6012   AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>(JS_GetRuntime(cx)));
  6013   if (!cinfo) {
  6014     JS_ReportOutOfMemory(cx);
  6015     return nullptr;
  6018   // Get the prototype of the FunctionType object, of class CTypeProto,
  6019   // which stores our JSContext for use with the closure.
  6020   RootedObject proto(cx);
  6021   if (!JS_GetPrototype(cx, typeObj, &proto))
  6022     return nullptr;
  6023   JS_ASSERT(proto);
  6024   JS_ASSERT(CType::IsCTypeProto(proto));
  6026   // Get a JSContext for use with the closure.
  6027   cinfo->cx = js::DefaultJSContext(JS_GetRuntime(cx));
  6029   // Prepare the error sentinel value. It's important to do this now, because
  6030   // we might be unable to convert the value to the proper type. If so, we want
  6031   // the caller to know about it _now_, rather than some uncertain time in the
  6032   // future when the error sentinel is actually needed.
  6033   if (!JSVAL_IS_VOID(errVal)) {
  6035     // Make sure the callback returns something.
  6036     if (CType::GetTypeCode(fninfo->mReturnType) == TYPE_void_t) {
  6037       JS_ReportError(cx, "A void callback can't pass an error sentinel");
  6038       return nullptr;
  6041     // With the exception of void, the FunctionType constructor ensures that
  6042     // the return type has a defined size.
  6043     JS_ASSERT(CType::IsSizeDefined(fninfo->mReturnType));
  6045     // Allocate a buffer for the return value.
  6046     size_t rvSize = CType::GetSize(fninfo->mReturnType);
  6047     cinfo->errResult = cx->malloc_(rvSize);
  6048     if (!cinfo->errResult)
  6049       return nullptr;
  6051     // Do the value conversion. This might fail, in which case we throw.
  6052     if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, cinfo->errResult,
  6053                          false, nullptr))
  6054       return nullptr;
  6055   } else {
  6056     cinfo->errResult = nullptr;
  6059   // Copy the important bits of context into cinfo.
  6060   cinfo->closureObj = result;
  6061   cinfo->typeObj = typeObj;
  6062   cinfo->thisObj = thisObj;
  6063   cinfo->jsfnObj = fnObj;
  6065   // Create an ffi_closure object and initialize it.
  6066   void* code;
  6067   cinfo->closure =
  6068     static_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &code));
  6069   if (!cinfo->closure || !code) {
  6070     JS_ReportError(cx, "couldn't create closure - libffi error");
  6071     return nullptr;
  6074   ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF,
  6075     CClosure::ClosureStub, cinfo.get(), code);
  6076   if (status != FFI_OK) {
  6077     JS_ReportError(cx, "couldn't create closure - libffi error");
  6078     return nullptr;
  6081   // Stash the ClosureInfo struct on our new object.
  6082   JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PRIVATE_TO_JSVAL(cinfo.forget()));
  6084   // Casting between void* and a function pointer is forbidden in C and C++.
  6085   // Do it via an integral type.
  6086   *fnptr = reinterpret_cast<PRFuncPtr>(reinterpret_cast<uintptr_t>(code));
  6087   return result;
  6090 void
  6091 CClosure::Trace(JSTracer* trc, JSObject* obj)
  6093   // Make sure our ClosureInfo slot is legit. If it's not, bail.
  6094   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
  6095   if (JSVAL_IS_VOID(slot))
  6096     return;
  6098   ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
  6100   // Identify our objects to the tracer. (There's no need to identify
  6101   // 'closureObj', since that's us.)
  6102   JS_CallHeapObjectTracer(trc, &cinfo->typeObj, "typeObj");
  6103   JS_CallHeapObjectTracer(trc, &cinfo->jsfnObj, "jsfnObj");
  6104   if (cinfo->thisObj)
  6105     JS_CallHeapObjectTracer(trc, &cinfo->thisObj, "thisObj");
  6108 void
  6109 CClosure::Finalize(JSFreeOp *fop, JSObject* obj)
  6111   // Make sure our ClosureInfo slot is legit. If it's not, bail.
  6112   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
  6113   if (JSVAL_IS_VOID(slot))
  6114     return;
  6116   ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
  6117   FreeOp::get(fop)->delete_(cinfo);
  6120 void
  6121 CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
  6123   JS_ASSERT(cif);
  6124   JS_ASSERT(result);
  6125   JS_ASSERT(args);
  6126   JS_ASSERT(userData);
  6128   // Retrieve the essentials from our closure object.
  6129   ClosureInfo* cinfo = static_cast<ClosureInfo*>(userData);
  6130   JSContext* cx = cinfo->cx;
  6132   // Let the runtime callback know that we are about to call into JS again. The end callback will
  6133   // fire automatically when we exit this function.
  6134   js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
  6135                                               js::CTYPES_CALLBACK_END);
  6137   RootedObject typeObj(cx, cinfo->typeObj);
  6138   RootedObject thisObj(cx, cinfo->thisObj);
  6139   RootedValue jsfnVal(cx, ObjectValue(*cinfo->jsfnObj));
  6141   JS_AbortIfWrongThread(JS_GetRuntime(cx));
  6143   JSAutoRequest ar(cx);
  6144   JSAutoCompartment ac(cx, cinfo->jsfnObj);
  6146   // Assert that our CIFs agree.
  6147   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
  6148   JS_ASSERT(cif == &fninfo->mCIF);
  6150   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
  6152   // Initialize the result to zero, in case something fails. Small integer types
  6153   // are promoted to a word-sized ffi_arg, so we must be careful to zero the
  6154   // whole word.
  6155   size_t rvSize = 0;
  6156   if (cif->rtype != &ffi_type_void) {
  6157     rvSize = cif->rtype->size;
  6158     switch (typeCode) {
  6159 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  6160     case TYPE_##name:
  6161 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6162 #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6163 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6164 #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6165 #include "ctypes/typedefs.h"
  6166       rvSize = Align(rvSize, sizeof(ffi_arg));
  6167       break;
  6168     default:
  6169       break;
  6171     memset(result, 0, rvSize);
  6174   // Set up an array for converted arguments.
  6175   JS::AutoValueVector argv(cx);
  6176   if (!argv.resize(cif->nargs)) {
  6177     JS_ReportOutOfMemory(cx);
  6178     return;
  6181   for (uint32_t i = 0; i < cif->nargs; ++i) {
  6182     // Convert each argument, and have any CData objects created depend on
  6183     // the existing buffers.
  6184     RootedObject argType(cx, fninfo->mArgTypes[i]);
  6185     if (!ConvertToJS(cx, argType, NullPtr(), args[i], false, false, &argv[i]))
  6186       return;
  6189   // Call the JS function. 'thisObj' may be nullptr, in which case the JS
  6190   // engine will find an appropriate object to use.
  6191   RootedValue rval(cx);
  6192   bool success = JS_CallFunctionValue(cx, thisObj, jsfnVal, argv, &rval);
  6194   // Convert the result. Note that we pass 'isArgument = false', such that
  6195   // ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char
  6196   // type, which would require an allocation that we can't track. The JS
  6197   // function must perform this conversion itself and return a PointerType
  6198   // CData; thusly, the burden of freeing the data is left to the user.
  6199   if (success && cif->rtype != &ffi_type_void)
  6200     success = ImplicitConvert(cx, rval, fninfo->mReturnType, result, false,
  6201                               nullptr);
  6203   if (!success) {
  6204     // Something failed. The callee may have thrown, or it may not have
  6205     // returned a value that ImplicitConvert() was happy with. Depending on how
  6206     // prudent the consumer has been, we may or may not have a recovery plan.
  6208     // In any case, a JS exception cannot be passed to C code, so report the
  6209     // exception if any and clear it from the cx.
  6210     if (JS_IsExceptionPending(cx))
  6211       JS_ReportPendingException(cx);
  6213     if (cinfo->errResult) {
  6214       // Good case: we have a sentinel that we can return. Copy it in place of
  6215       // the actual return value, and then proceed.
  6217       // The buffer we're returning might be larger than the size of the return
  6218       // type, due to libffi alignment issues (see above). But it should never
  6219       // be smaller.
  6220       size_t copySize = CType::GetSize(fninfo->mReturnType);
  6221       JS_ASSERT(copySize <= rvSize);
  6222       memcpy(result, cinfo->errResult, copySize);
  6223     } else {
  6224       // Bad case: not much we can do here. The rv is already zeroed out, so we
  6225       // just report (another) error and hope for the best. JS_ReportError will
  6226       // actually throw an exception here, so then we have to report it. Again.
  6227       // Ugh.
  6228       JS_ReportError(cx, "JavaScript callback failed, and an error sentinel "
  6229                          "was not specified.");
  6230       if (JS_IsExceptionPending(cx))
  6231         JS_ReportPendingException(cx);
  6233       return;
  6237   // Small integer types must be returned as a word-sized ffi_arg. Coerce it
  6238   // back into the size libffi expects.
  6239   switch (typeCode) {
  6240 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
  6241   case TYPE_##name:                                                            \
  6242     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
  6243       ffi_arg data = *static_cast<type*>(result);                              \
  6244       *static_cast<ffi_arg*>(result) = data;                                   \
  6245     }                                                                          \
  6246     break;
  6247 #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6248 #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6249 #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6250 #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
  6251 #include "ctypes/typedefs.h"
  6252   default:
  6253     break;
  6257 /*******************************************************************************
  6258 ** CData implementation
  6259 *******************************************************************************/
  6261 // Create a new CData object of type 'typeObj' containing binary data supplied
  6262 // in 'source', optionally with a referent object 'refObj'.
  6263 //
  6264 // * 'typeObj' must be a CType of defined (but possibly zero) size.
  6265 //
  6266 // * If an object 'refObj' is supplied, the new CData object stores the
  6267 //   referent object in a reserved slot for GC safety, such that 'refObj' will
  6268 //   be held alive by the resulting CData object. 'refObj' may or may not be
  6269 //   a CData object; merely an object we want to keep alive.
  6270 //   * If 'refObj' is a CData object, 'ownResult' must be false.
  6271 //   * Otherwise, 'refObj' is a Library or CClosure object, and 'ownResult'
  6272 //     may be true or false.
  6273 // * Otherwise 'refObj' is nullptr. In this case, 'ownResult' may be true or
  6274 //   false.
  6275 //
  6276 // * If 'ownResult' is true, the CData object will allocate an appropriately
  6277 //   sized buffer, and free it upon finalization. If 'source' data is
  6278 //   supplied, the data will be copied from 'source' into the buffer;
  6279 //   otherwise, the entirety of the new buffer will be initialized to zero.
  6280 // * If 'ownResult' is false, the new CData's buffer refers to a slice of
  6281 //   another buffer kept alive by 'refObj'. 'source' data must be provided,
  6282 //   and the new CData's buffer will refer to 'source'.
  6283 JSObject*
  6284 CData::Create(JSContext* cx,
  6285               HandleObject typeObj,
  6286               HandleObject refObj,
  6287               void* source,
  6288               bool ownResult)
  6290   JS_ASSERT(typeObj);
  6291   JS_ASSERT(CType::IsCType(typeObj));
  6292   JS_ASSERT(CType::IsSizeDefined(typeObj));
  6293   JS_ASSERT(ownResult || source);
  6294   JS_ASSERT_IF(refObj && CData::IsCData(refObj), !ownResult);
  6296   // Get the 'prototype' property from the type.
  6297   jsval slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
  6298   JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot));
  6300   RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
  6301   RootedObject parent(cx, JS_GetParent(typeObj));
  6302   JS_ASSERT(parent);
  6304   RootedObject dataObj(cx, JS_NewObject(cx, &sCDataClass, proto, parent));
  6305   if (!dataObj)
  6306     return nullptr;
  6308   // set the CData's associated type
  6309   JS_SetReservedSlot(dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj));
  6311   // Stash the referent object, if any, for GC safety.
  6312   if (refObj)
  6313     JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(refObj));
  6315   // Set our ownership flag.
  6316   JS_SetReservedSlot(dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult));
  6318   // attach the buffer. since it might not be 2-byte aligned, we need to
  6319   // allocate an aligned space for it and store it there. :(
  6320   char** buffer = cx->new_<char*>();
  6321   if (!buffer) {
  6322     JS_ReportOutOfMemory(cx);
  6323     return nullptr;
  6326   char* data;
  6327   if (!ownResult) {
  6328     data = static_cast<char*>(source);
  6329   } else {
  6330     // Initialize our own buffer.
  6331     size_t size = CType::GetSize(typeObj);
  6332     data = (char*)cx->malloc_(size);
  6333     if (!data) {
  6334       // Report a catchable allocation error.
  6335       JS_ReportAllocationOverflow(cx);
  6336       js_free(buffer);
  6337       return nullptr;
  6340     if (!source)
  6341       memset(data, 0, size);
  6342     else
  6343       memcpy(data, source, size);
  6346   *buffer = data;
  6347   JS_SetReservedSlot(dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer));
  6349   return dataObj;
  6352 void
  6353 CData::Finalize(JSFreeOp *fop, JSObject* obj)
  6355   // Delete our buffer, and the data it contains if we own it.
  6356   jsval slot = JS_GetReservedSlot(obj, SLOT_OWNS);
  6357   if (JSVAL_IS_VOID(slot))
  6358     return;
  6360   bool owns = JSVAL_TO_BOOLEAN(slot);
  6362   slot = JS_GetReservedSlot(obj, SLOT_DATA);
  6363   if (JSVAL_IS_VOID(slot))
  6364     return;
  6365   char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
  6367   if (owns)
  6368     FreeOp::get(fop)->free_(*buffer);
  6369   FreeOp::get(fop)->delete_(buffer);
  6372 JSObject*
  6373 CData::GetCType(JSObject* dataObj)
  6375   JS_ASSERT(CData::IsCData(dataObj));
  6377   jsval slot = JS_GetReservedSlot(dataObj, SLOT_CTYPE);
  6378   JSObject* typeObj = JSVAL_TO_OBJECT(slot);
  6379   JS_ASSERT(CType::IsCType(typeObj));
  6380   return typeObj;
  6383 void*
  6384 CData::GetData(JSObject* dataObj)
  6386   JS_ASSERT(CData::IsCData(dataObj));
  6388   jsval slot = JS_GetReservedSlot(dataObj, SLOT_DATA);
  6390   void** buffer = static_cast<void**>(JSVAL_TO_PRIVATE(slot));
  6391   JS_ASSERT(buffer);
  6392   JS_ASSERT(*buffer);
  6393   return *buffer;
  6396 bool
  6397 CData::IsCData(JSObject* obj)
  6399   return JS_GetClass(obj) == &sCDataClass;
  6402 bool
  6403 CData::IsCData(HandleValue v)
  6405   return v.isObject() && CData::IsCData(&v.toObject());
  6408 bool
  6409 CData::IsCDataProto(JSObject* obj)
  6411   return JS_GetClass(obj) == &sCDataProtoClass;
  6414 bool
  6415 CData::ValueGetter(JSContext* cx, JS::CallArgs args)
  6417   RootedObject obj(cx, &args.thisv().toObject());
  6419   // Convert the value to a primitive; do not create a new CData object.
  6420   RootedObject ctype(cx, GetCType(obj));
  6421   return ConvertToJS(cx, ctype, NullPtr(), GetData(obj), true, false, args.rval().address());
  6424 bool
  6425 CData::ValueSetter(JSContext* cx, JS::CallArgs args)
  6427   RootedObject obj(cx, &args.thisv().toObject());
  6428   args.rval().setUndefined();
  6429   return ImplicitConvert(cx, args.get(0), GetCType(obj), GetData(obj), false, nullptr);
  6432 bool
  6433 CData::Address(JSContext* cx, unsigned argc, jsval* vp)
  6435   CallArgs args = CallArgsFromVp(argc, vp);
  6436   if (args.length() != 0) {
  6437     JS_ReportError(cx, "address takes zero arguments");
  6438     return false;
  6441   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  6442   if (!obj)
  6443     return false;
  6444   if (!IsCData(obj)) {
  6445     JS_ReportError(cx, "not a CData");
  6446     return false;
  6449   RootedObject typeObj(cx, CData::GetCType(obj));
  6450   RootedObject pointerType(cx, PointerType::CreateInternal(cx, typeObj));
  6451   if (!pointerType)
  6452     return false;
  6454   // Create a PointerType CData object containing null.
  6455   JSObject* result = CData::Create(cx, pointerType, NullPtr(), nullptr, true);
  6456   if (!result)
  6457     return false;
  6459   args.rval().setObject(*result);
  6461   // Manually set the pointer inside the object, so we skip the conversion step.
  6462   void** data = static_cast<void**>(GetData(result));
  6463   *data = GetData(obj);
  6464   return true;
  6467 bool
  6468 CData::Cast(JSContext* cx, unsigned argc, jsval* vp)
  6470   CallArgs args = CallArgsFromVp(argc, vp);
  6471   if (args.length() != 2) {
  6472     JS_ReportError(cx, "cast takes two arguments");
  6473     return false;
  6476   if (JSVAL_IS_PRIMITIVE(args[0]) ||
  6477       !CData::IsCData(&args[0].toObject())) {
  6478     JS_ReportError(cx, "first argument must be a CData");
  6479     return false;
  6481   RootedObject sourceData(cx, &args[0].toObject());
  6482   JSObject* sourceType = CData::GetCType(sourceData);
  6484   if (JSVAL_IS_PRIMITIVE(args[1]) ||
  6485       !CType::IsCType(&args[1].toObject())) {
  6486     JS_ReportError(cx, "second argument must be a CType");
  6487     return false;
  6490   RootedObject targetType(cx, &args[1].toObject());
  6491   size_t targetSize;
  6492   if (!CType::GetSafeSize(targetType, &targetSize) ||
  6493       targetSize > CType::GetSize(sourceType)) {
  6494     JS_ReportError(cx,
  6495       "target CType has undefined or larger size than source CType");
  6496     return false;
  6499   // Construct a new CData object with a type of 'targetType' and a referent
  6500   // of 'sourceData'.
  6501   void* data = CData::GetData(sourceData);
  6502   JSObject* result = CData::Create(cx, targetType, sourceData, data, false);
  6503   if (!result)
  6504     return false;
  6506   args.rval().setObject(*result);
  6507   return true;
  6510 bool
  6511 CData::GetRuntime(JSContext* cx, unsigned argc, jsval* vp)
  6513   CallArgs args = CallArgsFromVp(argc, vp);
  6514   if (args.length() != 1) {
  6515     JS_ReportError(cx, "getRuntime takes one argument");
  6516     return false;
  6519   if (JSVAL_IS_PRIMITIVE(args[0]) ||
  6520       !CType::IsCType(&args[0].toObject())) {
  6521     JS_ReportError(cx, "first argument must be a CType");
  6522     return false;
  6525   RootedObject targetType(cx, &args[0].toObject());
  6526   size_t targetSize;
  6527   if (!CType::GetSafeSize(targetType, &targetSize) ||
  6528       targetSize != sizeof(void*)) {
  6529     JS_ReportError(cx, "target CType has non-pointer size");
  6530     return false;
  6533   void* data = static_cast<void*>(cx->runtime());
  6534   JSObject* result = CData::Create(cx, targetType, NullPtr(), &data, true);
  6535   if (!result)
  6536     return false;
  6538   args.rval().setObject(*result);
  6539   return true;
  6542 typedef JS::TwoByteCharsZ (*InflateUTF8Method)(JSContext *, const JS::UTF8Chars, size_t *);
  6544 static bool
  6545 ReadStringCommon(JSContext* cx, InflateUTF8Method inflateUTF8, unsigned argc, jsval *vp)
  6547   CallArgs args = CallArgsFromVp(argc, vp);
  6548   if (args.length() != 0) {
  6549     JS_ReportError(cx, "readString takes zero arguments");
  6550     return false;
  6553   JSObject* obj = CDataFinalizer::GetCData(cx, JS_THIS_OBJECT(cx, vp));
  6554   if (!obj || !CData::IsCData(obj)) {
  6555     JS_ReportError(cx, "not a CData");
  6556     return false;
  6559   // Make sure we are a pointer to, or an array of, an 8-bit or 16-bit
  6560   // character or integer type.
  6561   JSObject* baseType;
  6562   JSObject* typeObj = CData::GetCType(obj);
  6563   TypeCode typeCode = CType::GetTypeCode(typeObj);
  6564   void* data;
  6565   size_t maxLength = -1;
  6566   switch (typeCode) {
  6567   case TYPE_pointer:
  6568     baseType = PointerType::GetBaseType(typeObj);
  6569     data = *static_cast<void**>(CData::GetData(obj));
  6570     if (data == nullptr) {
  6571       JS_ReportError(cx, "cannot read contents of null pointer");
  6572       return false;
  6574     break;
  6575   case TYPE_array:
  6576     baseType = ArrayType::GetBaseType(typeObj);
  6577     data = CData::GetData(obj);
  6578     maxLength = ArrayType::GetLength(typeObj);
  6579     break;
  6580   default:
  6581     JS_ReportError(cx, "not a PointerType or ArrayType");
  6582     return false;
  6585   // Convert the string buffer, taking care to determine the correct string
  6586   // length in the case of arrays (which may contain embedded nulls).
  6587   JSString* result;
  6588   switch (CType::GetTypeCode(baseType)) {
  6589   case TYPE_int8_t:
  6590   case TYPE_uint8_t:
  6591   case TYPE_char:
  6592   case TYPE_signed_char:
  6593   case TYPE_unsigned_char: {
  6594     char* bytes = static_cast<char*>(data);
  6595     size_t length = strnlen(bytes, maxLength);
  6597     // Determine the length.
  6598     jschar *dst = inflateUTF8(cx, JS::UTF8Chars(bytes, length), &length).get();
  6599     if (!dst)
  6600       return false;
  6602     result = JS_NewUCString(cx, dst, length);
  6603     break;
  6605   case TYPE_int16_t:
  6606   case TYPE_uint16_t:
  6607   case TYPE_short:
  6608   case TYPE_unsigned_short:
  6609   case TYPE_jschar: {
  6610     jschar* chars = static_cast<jschar*>(data);
  6611     size_t length = strnlen(chars, maxLength);
  6612     result = JS_NewUCStringCopyN(cx, chars, length);
  6613     break;
  6615   default:
  6616     JS_ReportError(cx,
  6617       "base type is not an 8-bit or 16-bit integer or character type");
  6618     return false;
  6621   if (!result)
  6622     return false;
  6624   args.rval().setString(result);
  6625   return true;
  6628 bool
  6629 CData::ReadString(JSContext* cx, unsigned argc, jsval* vp)
  6631   return ReadStringCommon(cx, JS::UTF8CharsToNewTwoByteCharsZ, argc, vp);
  6634 bool
  6635 CData::ReadStringReplaceMalformed(JSContext* cx, unsigned argc, jsval* vp)
  6637   return ReadStringCommon(cx, JS::LossyUTF8CharsToNewTwoByteCharsZ, argc, vp);
  6640 JSString *
  6641 CData::GetSourceString(JSContext *cx, HandleObject typeObj, void *data)
  6643   // Walk the types, building up the toSource() string.
  6644   // First, we build up the type expression:
  6645   // 't.ptr' for pointers;
  6646   // 't.array([n])' for arrays;
  6647   // 'n' for structs, where n = t.name, the struct's name. (We assume this is
  6648   // bound to a variable in the current scope.)
  6649   AutoString source;
  6650   BuildTypeSource(cx, typeObj, true, source);
  6651   AppendString(source, "(");
  6652   if (!BuildDataSource(cx, typeObj, data, false, source))
  6653     return nullptr;
  6655   AppendString(source, ")");
  6657   return NewUCString(cx, source);
  6660 bool
  6661 CData::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  6663   CallArgs args = CallArgsFromVp(argc, vp);
  6664   if (args.length() != 0) {
  6665     JS_ReportError(cx, "toSource takes zero arguments");
  6666     return false;
  6669   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  6670   if (!obj)
  6671     return false;
  6672   if (!CData::IsCData(obj) && !CData::IsCDataProto(obj)) {
  6673     JS_ReportError(cx, "not a CData");
  6674     return false;
  6677   JSString* result;
  6678   if (CData::IsCData(obj)) {
  6679     RootedObject typeObj(cx, CData::GetCType(obj));
  6680     void* data = CData::GetData(obj);
  6682     result = CData::GetSourceString(cx, typeObj, data);
  6683   } else {
  6684     result = JS_NewStringCopyZ(cx, "[CData proto object]");
  6687   if (!result)
  6688     return false;
  6690   args.rval().setString(result);
  6691   return true;
  6694 bool
  6695 CData::ErrnoGetter(JSContext* cx, JS::CallArgs args)
  6697   args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_ERRNO));
  6698   return true;
  6701 #if defined(XP_WIN)
  6702 bool
  6703 CData::LastErrorGetter(JSContext* cx, JS::CallArgs args)
  6705   args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_LASTERROR));
  6706   return true;
  6708 #endif // defined(XP_WIN)
  6710 bool
  6711 CDataFinalizer::Methods::ToSource(JSContext *cx, unsigned argc, jsval *vp)
  6713   CallArgs args = CallArgsFromVp(argc, vp);
  6714   RootedObject objThis(cx, JS_THIS_OBJECT(cx, vp));
  6715   if (!objThis)
  6716     return false;
  6717   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
  6718     JS_ReportError(cx, "not a CDataFinalizer");
  6719     return false;
  6722   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  6723     JS_GetPrivate(objThis);
  6725   JSString *strMessage;
  6726   if (!p) {
  6727     strMessage = JS_NewStringCopyZ(cx, "ctypes.CDataFinalizer()");
  6728   } else {
  6729     RootedObject objType(cx, CDataFinalizer::GetCType(cx, objThis));
  6730     if (!objType) {
  6731       JS_ReportError(cx, "CDataFinalizer has no type");
  6732       return false;
  6735     AutoString source;
  6736     AppendString(source, "ctypes.CDataFinalizer(");
  6737     JSString *srcValue = CData::GetSourceString(cx, objType, p->cargs);
  6738     if (!srcValue) {
  6739       return false;
  6741     AppendString(source, srcValue);
  6742     AppendString(source, ", ");
  6743     jsval valCodePtrType = JS_GetReservedSlot(objThis,
  6744                                               SLOT_DATAFINALIZER_CODETYPE);
  6745     if (JSVAL_IS_PRIMITIVE(valCodePtrType)) {
  6746       return false;
  6749     RootedObject typeObj(cx, JSVAL_TO_OBJECT(valCodePtrType));
  6750     JSString *srcDispose = CData::GetSourceString(cx, typeObj, &(p->code));
  6751     if (!srcDispose) {
  6752       return false;
  6755     AppendString(source, srcDispose);
  6756     AppendString(source, ")");
  6757     strMessage = NewUCString(cx, source);
  6760   if (!strMessage) {
  6761     // This is a memory issue, no error message
  6762     return false;
  6765   args.rval().setString(strMessage);
  6766   return true;
  6769 bool
  6770 CDataFinalizer::Methods::ToString(JSContext *cx, unsigned argc, jsval *vp)
  6772   CallArgs args = CallArgsFromVp(argc, vp);
  6773   JSObject* objThis = JS_THIS_OBJECT(cx, vp);
  6774   if (!objThis)
  6775     return false;
  6776   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
  6777     JS_ReportError(cx, "not a CDataFinalizer");
  6778     return false;
  6781   JSString *strMessage;
  6782   RootedValue value(cx);
  6783   if (!JS_GetPrivate(objThis)) {
  6784     // Pre-check whether CDataFinalizer::GetValue can fail
  6785     // to avoid reporting an error when not appropriate.
  6786     strMessage = JS_NewStringCopyZ(cx, "[CDataFinalizer - empty]");
  6787     if (!strMessage) {
  6788       return false;
  6790   } else if (!CDataFinalizer::GetValue(cx, objThis, value.address())) {
  6791     MOZ_ASSUME_UNREACHABLE("Could not convert an empty CDataFinalizer");
  6792   } else {
  6793     strMessage = ToString(cx, value);
  6794     if (!strMessage) {
  6795       return false;
  6798   args.rval().setString(strMessage);
  6799   return true;
  6802 bool
  6803 CDataFinalizer::IsCDataFinalizer(JSObject *obj)
  6805   return JS_GetClass(obj) == &sCDataFinalizerClass;
  6809 JSObject *
  6810 CDataFinalizer::GetCType(JSContext *cx, JSObject *obj)
  6812   MOZ_ASSERT(IsCDataFinalizer(obj));
  6814   jsval valData = JS_GetReservedSlot(obj,
  6815                                      SLOT_DATAFINALIZER_VALTYPE);
  6816   if (JSVAL_IS_VOID(valData)) {
  6817     return nullptr;
  6820   return JSVAL_TO_OBJECT(valData);
  6823 JSObject*
  6824 CDataFinalizer::GetCData(JSContext *cx, JSObject *obj)
  6826   if (!obj) {
  6827     JS_ReportError(cx, "No C data");
  6828     return nullptr;
  6830   if (CData::IsCData(obj)) {
  6831     return obj;
  6833   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  6834     JS_ReportError(cx, "Not C data");
  6835     return nullptr;
  6837   RootedValue val(cx);
  6838   if (!CDataFinalizer::GetValue(cx, obj, val.address()) || JSVAL_IS_PRIMITIVE(val)) {
  6839     JS_ReportError(cx, "Empty CDataFinalizer");
  6840     return nullptr;
  6842   return JSVAL_TO_OBJECT(val);
  6845 bool
  6846 CDataFinalizer::GetValue(JSContext *cx, JSObject *obj, jsval *aResult)
  6848   MOZ_ASSERT(IsCDataFinalizer(obj));
  6850   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  6851     JS_GetPrivate(obj);
  6853   if (!p) {
  6854     JS_ReportError(cx, "Attempting to get the value of an empty CDataFinalizer");
  6855     return false;  // We have called |dispose| or |forget| already.
  6858   RootedObject ctype(cx, GetCType(cx, obj));
  6859   return ConvertToJS(cx, ctype, /*parent*/NullPtr(), p -> cargs, false, true, aResult);
  6862 /*
  6863  * Attach a C function as a finalizer to a JS object.
  6865  * Pseudo-JS signature:
  6866  * function(CData<T>, CData<T -> U>): CDataFinalizer<T>
  6867  *          value,    finalizer
  6869  * This function attaches strong references to the following values:
  6870  * - the CType of |value|
  6872  * Note: This function takes advantage of the fact that non-variadic
  6873  * CData functions are initialized during creation.
  6874  */
  6875 bool
  6876 CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval *vp)
  6878   CallArgs args = CallArgsFromVp(argc, vp);
  6879   RootedObject objSelf(cx, &args.callee());
  6880   RootedObject objProto(cx);
  6881   if (!GetObjectProperty(cx, objSelf, "prototype", &objProto)) {
  6882     JS_ReportError(cx, "CDataFinalizer.prototype does not exist");
  6883     return false;
  6886   // Get arguments
  6887   if (args.length() == 0) { // Special case: the empty (already finalized) object
  6888     JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
  6889     args.rval().setObject(*objResult);
  6890     return true;
  6893   if (args.length() != 2) {
  6894     JS_ReportError(cx, "CDataFinalizer takes 2 arguments");
  6895     return false;
  6898   JS::HandleValue valCodePtr = args[1];
  6899   if (!valCodePtr.isObject()) {
  6900     return TypeError(cx, "_a CData object_ of a function pointer type",
  6901                      valCodePtr);
  6903   JSObject *objCodePtr = &valCodePtr.toObject();
  6905   //Note: Using a custom argument formatter here would be awkward (requires
  6906   //a destructor just to uninstall the formatter).
  6908   // 2. Extract argument type of |objCodePtr|
  6909   if (!CData::IsCData(objCodePtr)) {
  6910     return TypeError(cx, "a _CData_ object of a function pointer type",
  6911                      valCodePtr);
  6913   RootedObject objCodePtrType(cx, CData::GetCType(objCodePtr));
  6914   RootedValue valCodePtrType(cx, ObjectValue(*objCodePtrType));
  6915   MOZ_ASSERT(objCodePtrType);
  6917   TypeCode typCodePtr = CType::GetTypeCode(objCodePtrType);
  6918   if (typCodePtr != TYPE_pointer) {
  6919     return TypeError(cx, "a CData object of a function _pointer_ type",
  6920                      valCodePtrType);
  6923   JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType);
  6924   MOZ_ASSERT(objCodeType);
  6926   TypeCode typCode = CType::GetTypeCode(objCodeType);
  6927   if (typCode != TYPE_function) {
  6928     return TypeError(cx, "a CData object of a _function_ pointer type",
  6929                      valCodePtrType);
  6931   uintptr_t code = *reinterpret_cast<uintptr_t*>(CData::GetData(objCodePtr));
  6932   if (!code) {
  6933     return TypeError(cx, "a CData object of a _non-NULL_ function pointer type",
  6934                      valCodePtrType);
  6937   FunctionInfo* funInfoFinalizer =
  6938     FunctionType::GetFunctionInfo(objCodeType);
  6939   MOZ_ASSERT(funInfoFinalizer);
  6941   if ((funInfoFinalizer->mArgTypes.length() != 1)
  6942       || (funInfoFinalizer->mIsVariadic)) {
  6943     RootedValue valCodeType(cx, ObjectValue(*objCodeType));
  6944     return TypeError(cx, "a function accepting exactly one argument",
  6945                      valCodeType);
  6947   RootedObject objArgType(cx, funInfoFinalizer->mArgTypes[0]);
  6948   RootedObject returnType(cx, funInfoFinalizer->mReturnType);
  6950   // Invariant: At this stage, we know that funInfoFinalizer->mIsVariadic
  6951   // is |false|. Therefore, funInfoFinalizer->mCIF has already been initialized.
  6953   bool freePointer = false;
  6955   // 3. Perform dynamic cast of |args[0]| into |objType|, store it in |cargs|
  6957   size_t sizeArg;
  6958   RootedValue valData(cx, args[0]);
  6959   if (!CType::GetSafeSize(objArgType, &sizeArg)) {
  6960     return TypeError(cx, "(an object with known size)", valData);
  6963   ScopedJSFreePtr<void> cargs(malloc(sizeArg));
  6965   if (!ImplicitConvert(cx, valData, objArgType, cargs.get(),
  6966                        false, &freePointer)) {
  6967     RootedValue valArgType(cx, ObjectValue(*objArgType));
  6968     return TypeError(cx, "(an object that can be converted to the following type)",
  6969                      valArgType);
  6971   if (freePointer) {
  6972     // Note: We could handle that case, if necessary.
  6973     JS_ReportError(cx, "Internal Error during CDataFinalizer. Object cannot be represented");
  6974     return false;
  6977   // 4. Prepare buffer for holding return value
  6979   ScopedJSFreePtr<void> rvalue;
  6980   if (CType::GetTypeCode(returnType) != TYPE_void_t) {
  6981     rvalue = malloc(Align(CType::GetSize(returnType),
  6982                           sizeof(ffi_arg)));
  6983   } //Otherwise, simply do not allocate
  6985   // 5. Create |objResult|
  6987   JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
  6988   if (!objResult) {
  6989     return false;
  6992   // If our argument is a CData, it holds a type.
  6993   // This is the type that we should capture, not that
  6994   // of the function, which may be less precise.
  6995   JSObject *objBestArgType = objArgType;
  6996   if (!JSVAL_IS_PRIMITIVE(valData)) {
  6997     JSObject *objData = &valData.toObject();
  6998     if (CData::IsCData(objData)) {
  6999       objBestArgType = CData::GetCType(objData);
  7000       size_t sizeBestArg;
  7001       if (!CType::GetSafeSize(objBestArgType, &sizeBestArg)) {
  7002         MOZ_ASSUME_UNREACHABLE("object with unknown size");
  7004       if (sizeBestArg != sizeArg) {
  7005         return TypeError(cx, "(an object with the same size as that expected by the C finalization function)", valData);
  7010   // Used by GetCType
  7011   JS_SetReservedSlot(objResult,
  7012                      SLOT_DATAFINALIZER_VALTYPE,
  7013                      OBJECT_TO_JSVAL(objBestArgType));
  7015   // Used by ToSource
  7016   JS_SetReservedSlot(objResult,
  7017                      SLOT_DATAFINALIZER_CODETYPE,
  7018                      OBJECT_TO_JSVAL(objCodePtrType));
  7020   ffi_abi abi;
  7021   if (!GetABI(cx, OBJECT_TO_JSVAL(funInfoFinalizer->mABI), &abi)) {
  7022     JS_ReportError(cx, "Internal Error: "
  7023                    "Invalid ABI specification in CDataFinalizer");
  7024     return false;
  7027   ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType);
  7028   if (!rtype) {
  7029     JS_ReportError(cx, "Internal Error: "
  7030                    "Could not access ffi type of CDataFinalizer");
  7031     return false;
  7034   // 7. Store C information as private
  7035   ScopedJSFreePtr<CDataFinalizer::Private>
  7036     p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private)));
  7038   memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif));
  7040   p->cargs = cargs.forget();
  7041   p->rvalue = rvalue.forget();
  7042   p->cargs_size = sizeArg;
  7043   p->code = code;
  7046   JS_SetPrivate(objResult, p.forget());
  7047   args.rval().setObject(*objResult);
  7048   return true;
  7052 /*
  7053  * Actually call the finalizer. Does not perform any cleanup on the object.
  7055  * Preconditions: |this| must be a |CDataFinalizer|, |p| must be non-null.
  7056  * The function fails if |this| has gone through |Forget|/|Dispose|
  7057  * or |Finalize|.
  7059  * This function does not alter the value of |errno|/|GetLastError|.
  7061  * If argument |errnoStatus| is non-nullptr, it receives the value of |errno|
  7062  * immediately after the call. Under Windows, if argument |lastErrorStatus|
  7063  * is non-nullptr, it receives the value of |GetLastError| immediately after
  7064  * the call. On other platforms, |lastErrorStatus| is ignored.
  7065  */
  7066 void
  7067 CDataFinalizer::CallFinalizer(CDataFinalizer::Private *p,
  7068                               int* errnoStatus,
  7069                               int32_t* lastErrorStatus)
  7071   int savedErrno = errno;
  7072   errno = 0;
  7073 #if defined(XP_WIN)
  7074   int32_t savedLastError = GetLastError();
  7075   SetLastError(0);
  7076 #endif // defined(XP_WIN)
  7078   ffi_call(&p->CIF, FFI_FN(p->code), p->rvalue, &p->cargs);
  7080   if (errnoStatus) {
  7081     *errnoStatus = errno;
  7083   errno = savedErrno;
  7084 #if defined(XP_WIN)
  7085   if (lastErrorStatus) {
  7086     *lastErrorStatus = GetLastError();
  7088   SetLastError(savedLastError);
  7089 #endif // defined(XP_WIN)
  7092 /*
  7093  * Forget the value.
  7095  * Preconditions: |this| must be a |CDataFinalizer|.
  7096  * The function fails if |this| has gone through |Forget|/|Dispose|
  7097  * or |Finalize|.
  7099  * Does not call the finalizer. Cleans up the Private memory and releases all
  7100  * strong references.
  7101  */
  7102 bool
  7103 CDataFinalizer::Methods::Forget(JSContext* cx, unsigned argc, jsval *vp)
  7105   CallArgs args = CallArgsFromVp(argc, vp);
  7106   if (args.length() != 0) {
  7107     JS_ReportError(cx, "CDataFinalizer.prototype.forget takes no arguments");
  7108     return false;
  7111   JS::Rooted<JSObject*> obj(cx, args.thisv().toObjectOrNull());
  7112   if (!obj)
  7113     return false;
  7114   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  7115     RootedValue val(cx, ObjectValue(*obj));
  7116     return TypeError(cx, "a CDataFinalizer", val);
  7119   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  7120     JS_GetPrivate(obj);
  7122   if (!p) {
  7123     JS_ReportError(cx, "forget called on an empty CDataFinalizer");
  7124     return false;
  7127   RootedValue valJSData(cx);
  7128   RootedObject ctype(cx, GetCType(cx, obj));
  7129   if (!ConvertToJS(cx, ctype, NullPtr(), p->cargs, false, true, valJSData.address())) {
  7130     JS_ReportError(cx, "CDataFinalizer value cannot be represented");
  7131     return false;
  7134   CDataFinalizer::Cleanup(p, obj);
  7136   args.rval().set(valJSData);
  7137   return true;
  7140 /*
  7141  * Clean up the value.
  7143  * Preconditions: |this| must be a |CDataFinalizer|.
  7144  * The function fails if |this| has gone through |Forget|/|Dispose|
  7145  * or |Finalize|.
  7147  * Calls the finalizer, cleans up the Private memory and releases all
  7148  * strong references.
  7149  */
  7150 bool
  7151 CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, jsval *vp)
  7153   CallArgs args = CallArgsFromVp(argc, vp);
  7154   if (args.length() != 0) {
  7155     JS_ReportError(cx, "CDataFinalizer.prototype.dispose takes no arguments");
  7156     return false;
  7159   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
  7160   if (!obj)
  7161     return false;
  7162   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
  7163     RootedValue val(cx, ObjectValue(*obj));
  7164     return TypeError(cx, "a CDataFinalizer", val);
  7167   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  7168     JS_GetPrivate(obj);
  7170   if (!p) {
  7171     JS_ReportError(cx, "dispose called on an empty CDataFinalizer.");
  7172     return false;
  7175   jsval valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE);
  7176   JS_ASSERT(!JSVAL_IS_PRIMITIVE(valType));
  7178   JSObject *objCTypes = CType::GetGlobalCTypes(cx, &valType.toObject());
  7179   if (!objCTypes)
  7180     return false;
  7182   jsval valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE);
  7183   JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCodePtrType));
  7184   JSObject *objCodePtrType = &valCodePtrType.toObject();
  7186   JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType);
  7187   JS_ASSERT(objCodeType);
  7188   JS_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function);
  7190   RootedObject resultType(cx, FunctionType::GetFunctionInfo(objCodeType)->mReturnType);
  7191   RootedValue result(cx, JSVAL_VOID);
  7193   int errnoStatus;
  7194 #if defined(XP_WIN)
  7195   int32_t lastErrorStatus;
  7196   CDataFinalizer::CallFinalizer(p, &errnoStatus, &lastErrorStatus);
  7197 #else
  7198   CDataFinalizer::CallFinalizer(p, &errnoStatus, nullptr);
  7199 #endif // defined(XP_WIN)
  7201   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
  7202 #if defined(XP_WIN)
  7203   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
  7204 #endif // defined(XP_WIN)
  7206   if (ConvertToJS(cx, resultType, NullPtr(), p->rvalue, false, true, result.address())) {
  7207     CDataFinalizer::Cleanup(p, obj);
  7208     args.rval().set(result);
  7209     return true;
  7211   CDataFinalizer::Cleanup(p, obj);
  7212   return false;
  7215 /*
  7216  * Perform finalization.
  7218  * Preconditions: |this| must be the result of |CDataFinalizer|.
  7219  * It may have gone through |Forget|/|Dispose|.
  7221  * If |this| has not gone through |Forget|/|Dispose|, calls the
  7222  * finalizer, cleans up the Private memory and releases all
  7223  * strong references.
  7224  */
  7225 void
  7226 CDataFinalizer::Finalize(JSFreeOp* fop, JSObject* obj)
  7228   CDataFinalizer::Private *p = (CDataFinalizer::Private *)
  7229     JS_GetPrivate(obj);
  7231   if (!p) {
  7232     return;
  7235   CDataFinalizer::CallFinalizer(p, nullptr, nullptr);
  7236   CDataFinalizer::Cleanup(p, nullptr);
  7239 /*
  7240  * Perform cleanup of a CDataFinalizer
  7242  * Release strong references, cleanup |Private|.
  7244  * Argument |p| contains the private information of the CDataFinalizer. If
  7245  * nullptr, this function does nothing.
  7246  * Argument |obj| should contain |nullptr| during finalization (or in any
  7247  * context in which the object itself should not be cleaned up), or a
  7248  * CDataFinalizer object otherwise.
  7249  */
  7250 void
  7251 CDataFinalizer::Cleanup(CDataFinalizer::Private *p, JSObject *obj)
  7253   if (!p) {
  7254     return;  // We have already cleaned up
  7257   free(p->cargs);
  7258   free(p->rvalue);
  7259   free(p);
  7261   if (!obj) {
  7262     return;  // No slots to clean up
  7265   JS_ASSERT(CDataFinalizer::IsCDataFinalizer(obj));
  7267   JS_SetPrivate(obj, nullptr);
  7268   for (int i = 0; i < CDATAFINALIZER_SLOTS; ++i) {
  7269     JS_SetReservedSlot(obj, i, JSVAL_NULL);
  7274 /*******************************************************************************
  7275 ** Int64 and UInt64 implementation
  7276 *******************************************************************************/
  7278 JSObject*
  7279 Int64Base::Construct(JSContext* cx,
  7280                      HandleObject proto,
  7281                      uint64_t data,
  7282                      bool isUnsigned)
  7284   const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
  7285   RootedObject parent(cx, JS_GetParent(proto));
  7286   RootedObject result(cx, JS_NewObject(cx, clasp, proto, parent));
  7287   if (!result)
  7288     return nullptr;
  7290   // attach the Int64's data
  7291   uint64_t* buffer = cx->new_<uint64_t>(data);
  7292   if (!buffer) {
  7293     JS_ReportOutOfMemory(cx);
  7294     return nullptr;
  7297   JS_SetReservedSlot(result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer));
  7299   if (!JS_FreezeObject(cx, result))
  7300     return nullptr;
  7302   return result;
  7305 void
  7306 Int64Base::Finalize(JSFreeOp *fop, JSObject* obj)
  7308   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
  7309   if (JSVAL_IS_VOID(slot))
  7310     return;
  7312   FreeOp::get(fop)->delete_(static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot)));
  7315 uint64_t
  7316 Int64Base::GetInt(JSObject* obj) {
  7317   JS_ASSERT(Int64::IsInt64(obj) || UInt64::IsUInt64(obj));
  7319   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
  7320   return *static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot));
  7323 bool
  7324 Int64Base::ToString(JSContext* cx,
  7325                     JSObject* obj,
  7326                     const CallArgs& args,
  7327                     bool isUnsigned)
  7329   if (args.length() > 1) {
  7330     JS_ReportError(cx, "toString takes zero or one argument");
  7331     return false;
  7334   int radix = 10;
  7335   if (args.length() == 1) {
  7336     jsval arg = args[0];
  7337     if (arg.isInt32())
  7338       radix = arg.toInt32();
  7339     if (!arg.isInt32() || radix < 2 || radix > 36) {
  7340       JS_ReportError(cx, "radix argument must be an integer between 2 and 36");
  7341       return false;
  7345   AutoString intString;
  7346   if (isUnsigned) {
  7347     IntegerToString(GetInt(obj), radix, intString);
  7348   } else {
  7349     IntegerToString(static_cast<int64_t>(GetInt(obj)), radix, intString);
  7352   JSString *result = NewUCString(cx, intString);
  7353   if (!result)
  7354     return false;
  7356   args.rval().setString(result);
  7357   return true;
  7360 bool
  7361 Int64Base::ToSource(JSContext* cx,
  7362                     JSObject* obj,
  7363                     const CallArgs& args,
  7364                     bool isUnsigned)
  7366   if (args.length() != 0) {
  7367     JS_ReportError(cx, "toSource takes zero arguments");
  7368     return false;
  7371   // Return a decimal string suitable for constructing the number.
  7372   AutoString source;
  7373   if (isUnsigned) {
  7374     AppendString(source, "ctypes.UInt64(\"");
  7375     IntegerToString(GetInt(obj), 10, source);
  7376   } else {
  7377     AppendString(source, "ctypes.Int64(\"");
  7378     IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
  7380   AppendString(source, "\")");
  7382   JSString *result = NewUCString(cx, source);
  7383   if (!result)
  7384     return false;
  7386   args.rval().setString(result);
  7387   return true;
  7390 bool
  7391 Int64::Construct(JSContext* cx,
  7392                  unsigned argc,
  7393                  jsval* vp)
  7395   CallArgs args = CallArgsFromVp(argc, vp);
  7397   // Construct and return a new Int64 object.
  7398   if (args.length() != 1) {
  7399     JS_ReportError(cx, "Int64 takes one argument");
  7400     return false;
  7403   int64_t i = 0;
  7404   if (!jsvalToBigInteger(cx, args[0], true, &i))
  7405     return TypeError(cx, "int64", args[0]);
  7407   // Get ctypes.Int64.prototype from the 'prototype' property of the ctor.
  7408   RootedValue slot(cx);
  7409   RootedObject callee(cx, &args.callee());
  7410   ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
  7411   RootedObject proto(cx, JSVAL_TO_OBJECT(slot));
  7412   JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
  7414   JSObject* result = Int64Base::Construct(cx, proto, i, false);
  7415   if (!result)
  7416     return false;
  7418   args.rval().setObject(*result);
  7419   return true;
  7422 bool
  7423 Int64::IsInt64(JSObject* obj)
  7425   return JS_GetClass(obj) == &sInt64Class;
  7428 bool
  7429 Int64::ToString(JSContext* cx, unsigned argc, jsval* vp)
  7431   CallArgs args = CallArgsFromVp(argc, vp);
  7432   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  7433   if (!obj)
  7434     return false;
  7435   if (!Int64::IsInt64(obj)) {
  7436     JS_ReportError(cx, "not an Int64");
  7437     return false;
  7440   return Int64Base::ToString(cx, obj, args, false);
  7443 bool
  7444 Int64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  7446   CallArgs args = CallArgsFromVp(argc, vp);
  7447   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  7448   if (!obj)
  7449     return false;
  7450   if (!Int64::IsInt64(obj)) {
  7451     JS_ReportError(cx, "not an Int64");
  7452     return false;
  7455   return Int64Base::ToSource(cx, obj, args, false);
  7458 bool
  7459 Int64::Compare(JSContext* cx, unsigned argc, jsval* vp)
  7461   CallArgs args = CallArgsFromVp(argc, vp);
  7462   if (args.length() != 2 ||
  7463       JSVAL_IS_PRIMITIVE(args[0]) ||
  7464       JSVAL_IS_PRIMITIVE(args[1]) ||
  7465       !Int64::IsInt64(&args[0].toObject()) ||
  7466       !Int64::IsInt64(&args[1].toObject())) {
  7467     JS_ReportError(cx, "compare takes two Int64 arguments");
  7468     return false;
  7471   JSObject* obj1 = &args[0].toObject();
  7472   JSObject* obj2 = &args[1].toObject();
  7474   int64_t i1 = Int64Base::GetInt(obj1);
  7475   int64_t i2 = Int64Base::GetInt(obj2);
  7477   if (i1 == i2)
  7478     args.rval().setInt32(0);
  7479   else if (i1 < i2)
  7480     args.rval().setInt32(-1);
  7481   else
  7482     args.rval().setInt32(1);
  7484   return true;
  7487 #define LO_MASK ((uint64_t(1) << 32) - 1)
  7488 #define INT64_LO(i) ((i) & LO_MASK)
  7489 #define INT64_HI(i) ((i) >> 32)
  7491 bool
  7492 Int64::Lo(JSContext* cx, unsigned argc, jsval* vp)
  7494   CallArgs args = CallArgsFromVp(argc, vp);
  7495   if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  7496       !Int64::IsInt64(&args[0].toObject())) {
  7497     JS_ReportError(cx, "lo takes one Int64 argument");
  7498     return false;
  7501   JSObject* obj = &args[0].toObject();
  7502   int64_t u = Int64Base::GetInt(obj);
  7503   double d = uint32_t(INT64_LO(u));
  7505   args.rval().setNumber(d);
  7506   return true;
  7509 bool
  7510 Int64::Hi(JSContext* cx, unsigned argc, jsval* vp)
  7512   CallArgs args = CallArgsFromVp(argc, vp);
  7513   if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  7514       !Int64::IsInt64(&args[0].toObject())) {
  7515     JS_ReportError(cx, "hi takes one Int64 argument");
  7516     return false;
  7519   JSObject* obj = &args[0].toObject();
  7520   int64_t u = Int64Base::GetInt(obj);
  7521   double d = int32_t(INT64_HI(u));
  7523   args.rval().setDouble(d);
  7524   return true;
  7527 bool
  7528 Int64::Join(JSContext* cx, unsigned argc, jsval* vp)
  7530   CallArgs args = CallArgsFromVp(argc, vp);
  7531   if (args.length() != 2) {
  7532     JS_ReportError(cx, "join takes two arguments");
  7533     return false;
  7536   int32_t hi;
  7537   uint32_t lo;
  7538   if (!jsvalToInteger(cx, args[0], &hi))
  7539     return TypeError(cx, "int32", args[0]);
  7540   if (!jsvalToInteger(cx, args[1], &lo))
  7541     return TypeError(cx, "uint32", args[1]);
  7543   int64_t i = (int64_t(hi) << 32) + int64_t(lo);
  7545   // Get Int64.prototype from the function's reserved slot.
  7546   JSObject* callee = &args.callee();
  7548   jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
  7549   RootedObject proto(cx, &slot.toObject());
  7550   JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
  7552   JSObject* result = Int64Base::Construct(cx, proto, i, false);
  7553   if (!result)
  7554     return false;
  7556   args.rval().setObject(*result);
  7557   return true;
  7560 bool
  7561 UInt64::Construct(JSContext* cx,
  7562                   unsigned argc,
  7563                   jsval* vp)
  7565   CallArgs args = CallArgsFromVp(argc, vp);
  7567   // Construct and return a new UInt64 object.
  7568   if (args.length() != 1) {
  7569     JS_ReportError(cx, "UInt64 takes one argument");
  7570     return false;
  7573   uint64_t u = 0;
  7574   if (!jsvalToBigInteger(cx, args[0], true, &u))
  7575     return TypeError(cx, "uint64", args[0]);
  7577   // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor.
  7578   RootedValue slot(cx);
  7579   RootedObject callee(cx, &args.callee());
  7580   ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
  7581   RootedObject proto(cx, &slot.toObject());
  7582   JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
  7584   JSObject* result = Int64Base::Construct(cx, proto, u, true);
  7585   if (!result)
  7586     return false;
  7588   args.rval().setObject(*result);
  7589   return true;
  7592 bool
  7593 UInt64::IsUInt64(JSObject* obj)
  7595   return JS_GetClass(obj) == &sUInt64Class;
  7598 bool
  7599 UInt64::ToString(JSContext* cx, unsigned argc, jsval* vp)
  7601   CallArgs args = CallArgsFromVp(argc, vp);
  7602   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  7603   if (!obj)
  7604     return false;
  7605   if (!UInt64::IsUInt64(obj)) {
  7606     JS_ReportError(cx, "not a UInt64");
  7607     return false;
  7610   return Int64Base::ToString(cx, obj, args, true);
  7613 bool
  7614 UInt64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
  7616   CallArgs args = CallArgsFromVp(argc, vp);
  7617   JSObject* obj = JS_THIS_OBJECT(cx, vp);
  7618   if (!obj)
  7619     return false;
  7620   if (!UInt64::IsUInt64(obj)) {
  7621     JS_ReportError(cx, "not a UInt64");
  7622     return false;
  7625   return Int64Base::ToSource(cx, obj, args, true);
  7628 bool
  7629 UInt64::Compare(JSContext* cx, unsigned argc, jsval* vp)
  7631   CallArgs args = CallArgsFromVp(argc, vp);
  7632   if (args.length() != 2 ||
  7633       JSVAL_IS_PRIMITIVE(args[0]) ||
  7634       JSVAL_IS_PRIMITIVE(args[1]) ||
  7635       !UInt64::IsUInt64(&args[0].toObject()) ||
  7636       !UInt64::IsUInt64(&args[1].toObject())) {
  7637     JS_ReportError(cx, "compare takes two UInt64 arguments");
  7638     return false;
  7641   JSObject* obj1 = &args[0].toObject();
  7642   JSObject* obj2 = &args[1].toObject();
  7644   uint64_t u1 = Int64Base::GetInt(obj1);
  7645   uint64_t u2 = Int64Base::GetInt(obj2);
  7647   if (u1 == u2)
  7648     args.rval().setInt32(0);
  7649   else if (u1 < u2)
  7650     args.rval().setInt32(-1);
  7651   else
  7652     args.rval().setInt32(1);
  7654   return true;
  7657 bool
  7658 UInt64::Lo(JSContext* cx, unsigned argc, jsval* vp)
  7660   CallArgs args = CallArgsFromVp(argc, vp);
  7661   if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  7662       !UInt64::IsUInt64(&args[0].toObject())) {
  7663     JS_ReportError(cx, "lo takes one UInt64 argument");
  7664     return false;
  7667   JSObject* obj = &args[0].toObject();
  7668   uint64_t u = Int64Base::GetInt(obj);
  7669   double d = uint32_t(INT64_LO(u));
  7671   args.rval().setDouble(d);
  7672   return true;
  7675 bool
  7676 UInt64::Hi(JSContext* cx, unsigned argc, jsval* vp)
  7678   CallArgs args = CallArgsFromVp(argc, vp);
  7679   if (args.length() != 1 || JSVAL_IS_PRIMITIVE(args[0]) ||
  7680       !UInt64::IsUInt64(&args[0].toObject())) {
  7681     JS_ReportError(cx, "hi takes one UInt64 argument");
  7682     return false;
  7685   JSObject* obj = &args[0].toObject();
  7686   uint64_t u = Int64Base::GetInt(obj);
  7687   double d = uint32_t(INT64_HI(u));
  7689   args.rval().setDouble(d);
  7690   return true;
  7693 bool
  7694 UInt64::Join(JSContext* cx, unsigned argc, jsval* vp)
  7696   CallArgs args = CallArgsFromVp(argc, vp);
  7697   if (args.length() != 2) {
  7698     JS_ReportError(cx, "join takes two arguments");
  7699     return false;
  7702   uint32_t hi;
  7703   uint32_t lo;
  7704   if (!jsvalToInteger(cx, args[0], &hi))
  7705     return TypeError(cx, "uint32_t", args[0]);
  7706   if (!jsvalToInteger(cx, args[1], &lo))
  7707     return TypeError(cx, "uint32_t", args[1]);
  7709   uint64_t u = (uint64_t(hi) << 32) + uint64_t(lo);
  7711   // Get UInt64.prototype from the function's reserved slot.
  7712   JSObject* callee = &args.callee();
  7714   jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
  7715   RootedObject proto(cx, &slot.toObject());
  7716   JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
  7718   JSObject* result = Int64Base::Construct(cx, proto, u, true);
  7719   if (!result)
  7720     return false;
  7722   args.rval().setObject(*result);
  7723   return true;

mercurial