LCOV - code coverage report
Current view: top level - js/src/ctypes - CTypes.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 268 3987 6.7 %
Date: 2017-07-14 16:53:18 Functions: 29 703 4.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "ctypes/CTypes.h"
       8             : 
       9             : #include "mozilla/FloatingPoint.h"
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "mozilla/SizePrintfMacros.h"
      12             : #include "mozilla/Sprintf.h"
      13             : #include "mozilla/Vector.h"
      14             : 
      15             : #include <limits>
      16             : #include <math.h>
      17             : #include <stdint.h>
      18             : 
      19             : #if defined(XP_WIN)
      20             : #include <float.h>
      21             : #endif
      22             : 
      23             : #if defined(SOLARIS)
      24             : #include <ieeefp.h>
      25             : #endif
      26             : 
      27             : #ifdef HAVE_SSIZE_T
      28             : #include <sys/types.h>
      29             : #endif
      30             : 
      31             : #if defined(XP_UNIX)
      32             : #include <errno.h>
      33             : #endif
      34             : 
      35             : #include "jscntxt.h"
      36             : #include "jsexn.h"
      37             : #include "jsfun.h"
      38             : #include "jsnum.h"
      39             : #include "jsprf.h"
      40             : #include "jswin.h"
      41             : 
      42             : #include "builtin/TypedObject.h"
      43             : #include "ctypes/Library.h"
      44             : #include "gc/Policy.h"
      45             : #include "gc/Zone.h"
      46             : #include "jit/AtomicOperations.h"
      47             : #include "js/Vector.h"
      48             : 
      49             : #include "jsatominlines.h"
      50             : #include "jsobjinlines.h"
      51             : 
      52             : using namespace std;
      53             : 
      54             : using JS::AutoCheckCannotGC;
      55             : 
      56             : namespace js {
      57             : namespace ctypes {
      58             : 
      59             : template <typename CharT>
      60             : size_t
      61           0 : GetDeflatedUTF8StringLength(JSContext* maybecx, const CharT* chars,
      62             :                             size_t nchars)
      63             : {
      64             :     size_t nbytes;
      65             :     const CharT* end;
      66             :     unsigned c, c2;
      67             : 
      68           0 :     nbytes = nchars;
      69           0 :     for (end = chars + nchars; chars != end; chars++) {
      70           0 :         c = *chars;
      71           0 :         if (c < 0x80)
      72           0 :             continue;
      73           0 :         if (0xD800 <= c && c <= 0xDFFF) {
      74             :             /* Surrogate pair. */
      75           0 :             chars++;
      76             : 
      77             :             /* nbytes sets 1 length since this is surrogate pair. */
      78           0 :             nbytes--;
      79           0 :             if (c >= 0xDC00 || chars == end)
      80             :                 goto bad_surrogate;
      81           0 :             c2 = *chars;
      82           0 :             if (c2 < 0xDC00 || c2 > 0xDFFF)
      83             :                 goto bad_surrogate;
      84           0 :             c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
      85             :         }
      86           0 :         c >>= 11;
      87           0 :         nbytes++;
      88           0 :         while (c) {
      89           0 :             c >>= 5;
      90           0 :             nbytes++;
      91             :         }
      92             :     }
      93           0 :     return nbytes;
      94             : 
      95             :   bad_surrogate:
      96           0 :     if (maybecx) {
      97           0 :         js::gc::AutoSuppressGC suppress(maybecx);
      98             :         char buffer[10];
      99           0 :         SprintfLiteral(buffer, "0x%x", c);
     100           0 :         JS_ReportErrorFlagsAndNumberASCII(maybecx, JSREPORT_ERROR,
     101             :                                           GetErrorMessage,
     102             :                                           nullptr, JSMSG_BAD_SURROGATE_CHAR,
     103             :                                           buffer);
     104             :     }
     105           0 :     return (size_t) -1;
     106             : }
     107             : 
     108             : template size_t
     109             : GetDeflatedUTF8StringLength(JSContext* maybecx, const Latin1Char* chars,
     110             :                             size_t nchars);
     111             : 
     112             : template size_t
     113             : GetDeflatedUTF8StringLength(JSContext* maybecx, const char16_t* chars,
     114             :                             size_t nchars);
     115             : 
     116             : static size_t
     117           0 : GetDeflatedUTF8StringLength(JSContext* maybecx, JSLinearString* str)
     118             : {
     119           0 :     size_t length = str->length();
     120             : 
     121           0 :     JS::AutoCheckCannotGC nogc;
     122           0 :     return str->hasLatin1Chars()
     123           0 :            ? GetDeflatedUTF8StringLength(maybecx, str->latin1Chars(nogc), length)
     124           0 :            : GetDeflatedUTF8StringLength(maybecx, str->twoByteChars(nogc), length);
     125             : }
     126             : 
     127             : template <typename CharT>
     128             : bool
     129           0 : DeflateStringToUTF8Buffer(JSContext* maybecx, const CharT* src, size_t srclen,
     130             :                           char* dst, size_t* dstlenp)
     131             : {
     132             :     size_t i, utf8Len;
     133             :     char16_t c, c2;
     134             :     uint32_t v;
     135             :     uint8_t utf8buf[6];
     136             : 
     137           0 :     size_t dstlen = *dstlenp;
     138           0 :     size_t origDstlen = dstlen;
     139             : 
     140           0 :     while (srclen) {
     141           0 :         c = *src++;
     142           0 :         srclen--;
     143           0 :         if (c >= 0xDC00 && c <= 0xDFFF)
     144           0 :             goto badSurrogate;
     145           0 :         if (c < 0xD800 || c > 0xDBFF) {
     146           0 :             v = c;
     147             :         } else {
     148           0 :             if (srclen < 1)
     149           0 :                 goto badSurrogate;
     150           0 :             c2 = *src;
     151           0 :             if ((c2 < 0xDC00) || (c2 > 0xDFFF))
     152             :                 goto badSurrogate;
     153           0 :             src++;
     154           0 :             srclen--;
     155           0 :             v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
     156             :         }
     157           0 :         if (v < 0x0080) {
     158             :             /* no encoding necessary - performance hack */
     159           0 :             if (dstlen == 0)
     160           0 :                 goto bufferTooSmall;
     161           0 :             *dst++ = (char) v;
     162           0 :             utf8Len = 1;
     163             :         } else {
     164           0 :             utf8Len = js::OneUcs4ToUtf8Char(utf8buf, v);
     165           0 :             if (utf8Len > dstlen)
     166           0 :                 goto bufferTooSmall;
     167           0 :             for (i = 0; i < utf8Len; i++)
     168           0 :                 *dst++ = (char) utf8buf[i];
     169             :         }
     170           0 :         dstlen -= utf8Len;
     171             :     }
     172           0 :     *dstlenp = (origDstlen - dstlen);
     173           0 :     return true;
     174             : 
     175             : badSurrogate:
     176           0 :     *dstlenp = (origDstlen - dstlen);
     177             :     /* Delegate error reporting to the measurement function. */
     178           0 :     if (maybecx)
     179           0 :         GetDeflatedUTF8StringLength(maybecx, src - 1, srclen + 1);
     180           0 :     return false;
     181             : 
     182             : bufferTooSmall:
     183           0 :     *dstlenp = (origDstlen - dstlen);
     184           0 :     if (maybecx) {
     185           0 :         js::gc::AutoSuppressGC suppress(maybecx);
     186           0 :         JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
     187             :                                   JSMSG_BUFFER_TOO_SMALL);
     188             :     }
     189           0 :     return false;
     190             : }
     191             : 
     192             : template bool
     193             : DeflateStringToUTF8Buffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
     194             :                           char* dst, size_t* dstlenp);
     195             : 
     196             : template bool
     197             : DeflateStringToUTF8Buffer(JSContext* maybecx, const char16_t* src, size_t srclen,
     198             :                           char* dst, size_t* dstlenp);
     199             : 
     200             : static bool
     201           0 : DeflateStringToUTF8Buffer(JSContext* maybecx, JSLinearString* str, char* dst,
     202             :                           size_t* dstlenp)
     203             : {
     204           0 :     size_t length = str->length();
     205             : 
     206           0 :     JS::AutoCheckCannotGC nogc;
     207           0 :     return str->hasLatin1Chars()
     208           0 :            ? DeflateStringToUTF8Buffer(maybecx, str->latin1Chars(nogc), length, dst, dstlenp)
     209           0 :            : DeflateStringToUTF8Buffer(maybecx, str->twoByteChars(nogc), length, dst, dstlenp);
     210             : }
     211             : 
     212             : /*******************************************************************************
     213             : ** JSAPI function prototypes
     214             : *******************************************************************************/
     215             : 
     216             : // We use an enclosing struct here out of paranoia about the ability of gcc 4.4
     217             : // (and maybe 4.5) to correctly compile this if it were a template function.
     218             : // See also the comments in dom/workers/Events.cpp (and other adjacent files) by
     219             : // the |struct Property| there.
     220             : template<JS::IsAcceptableThis Test, JS::NativeImpl Impl>
     221             : struct Property
     222             : {
     223             :   static bool
     224          85 :   Fun(JSContext* cx, unsigned argc, JS::Value* vp)
     225             :   {
     226          85 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     227          85 :     return JS::CallNonGenericMethod<Test, Impl>(cx, args);
     228             :   }
     229             : };
     230             : 
     231             : static bool ConstructAbstract(JSContext* cx, unsigned argc, Value* vp);
     232             : 
     233             : namespace CType {
     234             :   static bool ConstructData(JSContext* cx, unsigned argc, Value* vp);
     235             :   static bool ConstructBasic(JSContext* cx, HandleObject obj, const CallArgs& args);
     236             : 
     237             :   static void Trace(JSTracer* trc, JSObject* obj);
     238             :   static void Finalize(JSFreeOp* fop, JSObject* obj);
     239             : 
     240             :   bool IsCType(HandleValue v);
     241             :   bool IsCTypeOrProto(HandleValue v);
     242             : 
     243             :   bool PrototypeGetter(JSContext* cx, const JS::CallArgs& args);
     244             :   bool NameGetter(JSContext* cx, const JS::CallArgs& args);
     245             :   bool SizeGetter(JSContext* cx, const JS::CallArgs& args);
     246             :   bool PtrGetter(JSContext* cx, const JS::CallArgs& args);
     247             : 
     248             :   static bool CreateArray(JSContext* cx, unsigned argc, Value* vp);
     249             :   static bool ToString(JSContext* cx, unsigned argc, Value* vp);
     250             :   static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     251             :   static bool HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp);
     252             : 
     253             : 
     254             :   /*
     255             :    * Get the global "ctypes" object.
     256             :    *
     257             :    * |obj| must be a CType object.
     258             :    *
     259             :    * This function never returns nullptr.
     260             :    */
     261             :   static JSObject* GetGlobalCTypes(JSContext* cx, JSObject* obj);
     262             : 
     263             : } // namespace CType
     264             : 
     265             : namespace ABI {
     266             :   bool IsABI(JSObject* obj);
     267             :   static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     268             : } // namespace ABI
     269             : 
     270             : namespace PointerType {
     271             :   static bool Create(JSContext* cx, unsigned argc, Value* vp);
     272             :   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
     273             : 
     274             :   bool IsPointerType(HandleValue v);
     275             :   bool IsPointer(HandleValue v);
     276             : 
     277             :   bool TargetTypeGetter(JSContext* cx, const JS::CallArgs& args);
     278             :   bool ContentsGetter(JSContext* cx, const JS::CallArgs& args);
     279             :   bool ContentsSetter(JSContext* cx, const JS::CallArgs& args);
     280             : 
     281             :   static bool IsNull(JSContext* cx, unsigned argc, Value* vp);
     282             :   static bool Increment(JSContext* cx, unsigned argc, Value* vp);
     283             :   static bool Decrement(JSContext* cx, unsigned argc, Value* vp);
     284             :   // The following is not an instance function, since we don't want to expose arbitrary
     285             :   // pointer arithmetic at this moment.
     286             :   static bool OffsetBy(JSContext* cx, const CallArgs& args, int offset);
     287             : } // namespace PointerType
     288             : 
     289             : namespace ArrayType {
     290             :   bool IsArrayType(HandleValue v);
     291             :   bool IsArrayOrArrayType(HandleValue v);
     292             : 
     293             :   static bool Create(JSContext* cx, unsigned argc, Value* vp);
     294             :   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
     295             : 
     296             :   bool ElementTypeGetter(JSContext* cx, const JS::CallArgs& args);
     297             :   bool LengthGetter(JSContext* cx, const JS::CallArgs& args);
     298             : 
     299             :   static bool Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp);
     300             :   static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
     301             :                      ObjectOpResult& result);
     302             :   static bool AddressOfElement(JSContext* cx, unsigned argc, Value* vp);
     303             : } // namespace ArrayType
     304             : 
     305             : namespace StructType {
     306             :   bool IsStruct(HandleValue v);
     307             : 
     308             :   static bool Create(JSContext* cx, unsigned argc, Value* vp);
     309             :   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
     310             : 
     311             :   bool FieldsArrayGetter(JSContext* cx, const JS::CallArgs& args);
     312             : 
     313             :   enum {
     314             :     SLOT_FIELDNAME
     315             :   };
     316             : 
     317             :   static bool FieldGetter(JSContext* cx, unsigned argc, Value* vp);
     318             :   static bool FieldSetter(JSContext* cx, unsigned argc, Value* vp);
     319             :   static bool AddressOfField(JSContext* cx, unsigned argc, Value* vp);
     320             :   static bool Define(JSContext* cx, unsigned argc, Value* vp);
     321             : } // namespace StructType
     322             : 
     323             : namespace FunctionType {
     324             :   static bool Create(JSContext* cx, unsigned argc, Value* vp);
     325             :   static bool ConstructData(JSContext* cx, HandleObject typeObj,
     326             :     HandleObject dataObj, HandleObject fnObj, HandleObject thisObj, HandleValue errVal);
     327             : 
     328             :   static bool Call(JSContext* cx, unsigned argc, Value* vp);
     329             : 
     330             :   bool IsFunctionType(HandleValue v);
     331             : 
     332             :   bool ArgTypesGetter(JSContext* cx, const JS::CallArgs& args);
     333             :   bool ReturnTypeGetter(JSContext* cx, const JS::CallArgs& args);
     334             :   bool ABIGetter(JSContext* cx, const JS::CallArgs& args);
     335             :   bool IsVariadicGetter(JSContext* cx, const JS::CallArgs& args);
     336             : } // namespace FunctionType
     337             : 
     338             : namespace CClosure {
     339             :   static void Trace(JSTracer* trc, JSObject* obj);
     340             :   static void Finalize(JSFreeOp* fop, JSObject* obj);
     341             : 
     342             :   // libffi callback
     343             :   static void ClosureStub(ffi_cif* cif, void* result, void** args,
     344             :     void* userData);
     345             : 
     346             :   struct ArgClosure : public ScriptEnvironmentPreparer::Closure {
     347           0 :       ArgClosure(ffi_cif* cifArg, void* resultArg, void** argsArg, ClosureInfo* cinfoArg)
     348           0 :         : cif(cifArg), result(resultArg), args(argsArg), cinfo(cinfoArg) {}
     349             : 
     350             :       bool operator()(JSContext *cx) override;
     351             : 
     352             :       ffi_cif* cif;
     353             :       void* result;
     354             :       void** args;
     355             :       ClosureInfo* cinfo;
     356             :   };
     357             : } // namespace CClosure
     358             : 
     359             : namespace CData {
     360             :   static void Finalize(JSFreeOp* fop, JSObject* obj);
     361             : 
     362             :   bool ValueGetter(JSContext* cx, const JS::CallArgs& args);
     363             :   bool ValueSetter(JSContext* cx, const JS::CallArgs& args);
     364             : 
     365             :   static bool Address(JSContext* cx, unsigned argc, Value* vp);
     366             :   static bool ReadString(JSContext* cx, unsigned argc, Value* vp);
     367             :   static bool ReadStringReplaceMalformed(JSContext* cx, unsigned argc, Value* vp);
     368             :   static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     369             :   static JSString* GetSourceString(JSContext* cx, HandleObject typeObj,
     370             :                                    void* data);
     371             : 
     372             :   bool ErrnoGetter(JSContext* cx, const JS::CallArgs& args);
     373             : 
     374             : #if defined(XP_WIN)
     375             :   bool LastErrorGetter(JSContext* cx, const JS::CallArgs& args);
     376             : #endif // defined(XP_WIN)
     377             : } // namespace CData
     378             : 
     379             : namespace CDataFinalizer {
     380             :   /*
     381             :    * Attach a C function as a finalizer to a JS object.
     382             :    *
     383             :    * This function is available from JS as |ctypes.withFinalizer|.
     384             :    *
     385             :    * JavaScript signature:
     386             :    * function(CData, CData):   CDataFinalizer
     387             :    *          value  finalizer finalizable
     388             :    *
     389             :    * Where |finalizer| is a one-argument function taking a value
     390             :    * with the same type as |value|.
     391             :    */
     392             :   static bool Construct(JSContext* cx, unsigned argc, Value* vp);
     393             : 
     394             :   /*
     395             :    * Private data held by |CDataFinalizer|.
     396             :    *
     397             :    * See also |enum CDataFinalizerSlot| for the slots of
     398             :    * |CDataFinalizer|.
     399             :    *
     400             :    * Note: the private data may be nullptr, if |dispose|, |forget| or the
     401             :    * finalizer has already been called.
     402             :    */
     403             :   struct Private {
     404             :     /*
     405             :      * The C data to pass to the code.
     406             :      * Finalization/|dispose|/|forget| release this memory.
     407             :      */
     408             :     void* cargs;
     409             : 
     410             :     /*
     411             :      * The total size of the buffer pointed by |cargs|
     412             :      */
     413             :     size_t cargs_size;
     414             : 
     415             :     /*
     416             :      * Low-level signature information.
     417             :      * Finalization/|dispose|/|forget| release this memory.
     418             :      */
     419             :     ffi_cif CIF;
     420             : 
     421             :     /*
     422             :      * The C function to invoke during finalization.
     423             :      * Do not deallocate this.
     424             :      */
     425             :     uintptr_t code;
     426             : 
     427             :     /*
     428             :      * A buffer for holding the return value.
     429             :      * Finalization/|dispose|/|forget| release this memory.
     430             :      */
     431             :     void* rvalue;
     432             :   };
     433             : 
     434             :   /*
     435             :    * Methods of instances of |CDataFinalizer|
     436             :    */
     437             :   namespace Methods {
     438             :     static bool Dispose(JSContext* cx, unsigned argc, Value* vp);
     439             :     static bool Forget(JSContext* cx, unsigned argc, Value* vp);
     440             :     static bool ReadString(JSContext* cx, unsigned argc, Value* vp);
     441             :     static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     442             :     static bool ToString(JSContext* cx, unsigned argc, Value* vp);
     443             :   } // namespace Methods
     444             : 
     445             :   /*
     446             :    * Utility functions
     447             :    *
     448             :    * @return true if |obj| is a CDataFinalizer, false otherwise.
     449             :    */
     450             :   static bool IsCDataFinalizer(JSObject* obj);
     451             : 
     452             :   /*
     453             :    * Clean up the finalization information of a CDataFinalizer.
     454             :    *
     455             :    * Used by |Finalize|, |Dispose| and |Forget|.
     456             :    *
     457             :    * @param p The private information of the CDataFinalizer. If nullptr,
     458             :    * this function does nothing.
     459             :    * @param obj Either nullptr, if the object should not be cleaned up (i.e.
     460             :    * during finalization) or a CDataFinalizer JSObject. Always use nullptr
     461             :    * if you are calling from a finalizer.
     462             :    */
     463             :   static void Cleanup(Private* p, JSObject* obj);
     464             : 
     465             :   /*
     466             :    * Perform the actual call to the finalizer code.
     467             :    */
     468             :   static void CallFinalizer(CDataFinalizer::Private* p,
     469             :                             int* errnoStatus,
     470             :                             int32_t* lastErrorStatus);
     471             : 
     472             :   /*
     473             :    * Return the CType of a CDataFinalizer object, or nullptr if the object
     474             :    * has been cleaned-up already.
     475             :    */
     476             :   static JSObject* GetCType(JSContext* cx, JSObject* obj);
     477             : 
     478             :   /*
     479             :    * Perform finalization of a |CDataFinalizer|
     480             :    */
     481             :   static void Finalize(JSFreeOp* fop, JSObject* obj);
     482             : 
     483             :   /*
     484             :    * Return the Value contained by this finalizer.
     485             :    *
     486             :    * Note that the Value is actually not recorded, but converted back from C.
     487             :    */
     488             :   static bool GetValue(JSContext* cx, JSObject* obj, MutableHandleValue result);
     489             : 
     490             : } // namespace CDataFinalizer
     491             : 
     492             : 
     493             : // Int64Base provides functions common to Int64 and UInt64.
     494             : namespace Int64Base {
     495             :   JSObject* Construct(JSContext* cx, HandleObject proto, uint64_t data,
     496             :     bool isUnsigned);
     497             : 
     498             :   uint64_t GetInt(JSObject* obj);
     499             : 
     500             :   bool ToString(JSContext* cx, JSObject* obj, const CallArgs& args,
     501             :                 bool isUnsigned);
     502             : 
     503             :   bool ToSource(JSContext* cx, JSObject* obj, const CallArgs& args,
     504             :                 bool isUnsigned);
     505             : 
     506             :   static void Finalize(JSFreeOp* fop, JSObject* obj);
     507             : } // namespace Int64Base
     508             : 
     509             : namespace Int64 {
     510             :   static bool Construct(JSContext* cx, unsigned argc, Value* vp);
     511             : 
     512             :   static bool ToString(JSContext* cx, unsigned argc, Value* vp);
     513             :   static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     514             : 
     515             :   static bool Compare(JSContext* cx, unsigned argc, Value* vp);
     516             :   static bool Lo(JSContext* cx, unsigned argc, Value* vp);
     517             :   static bool Hi(JSContext* cx, unsigned argc, Value* vp);
     518             :   static bool Join(JSContext* cx, unsigned argc, Value* vp);
     519             : } // namespace Int64
     520             : 
     521             : namespace UInt64 {
     522             :   static bool Construct(JSContext* cx, unsigned argc, Value* vp);
     523             : 
     524             :   static bool ToString(JSContext* cx, unsigned argc, Value* vp);
     525             :   static bool ToSource(JSContext* cx, unsigned argc, Value* vp);
     526             : 
     527             :   static bool Compare(JSContext* cx, unsigned argc, Value* vp);
     528             :   static bool Lo(JSContext* cx, unsigned argc, Value* vp);
     529             :   static bool Hi(JSContext* cx, unsigned argc, Value* vp);
     530             :   static bool Join(JSContext* cx, unsigned argc, Value* vp);
     531             : } // namespace UInt64
     532             : 
     533             : /*******************************************************************************
     534             : ** JSClass definitions and initialization functions
     535             : *******************************************************************************/
     536             : 
     537             : // Class representing the 'ctypes' object itself. This exists to contain the
     538             : // JSCTypesCallbacks set of function pointers.
     539             : static const JSClass sCTypesGlobalClass = {
     540             :   "ctypes",
     541             :   JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS)
     542             : };
     543             : 
     544             : static const JSClass sCABIClass = {
     545             :   "CABI",
     546             :   JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS)
     547             : };
     548             : 
     549             : // Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype.
     550             : // This exists to give said prototypes a class of "CType", and to provide
     551             : // reserved slots for stashing various other prototype objects.
     552             : static const JSClassOps sCTypeProtoClassOps = {
     553             :   nullptr, nullptr, nullptr, nullptr,
     554             :   nullptr, nullptr, nullptr, nullptr,
     555             :   nullptr, ConstructAbstract, nullptr, ConstructAbstract
     556             : };
     557             : static const JSClass sCTypeProtoClass = {
     558             :   "CType",
     559             :   JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
     560             :   &sCTypeProtoClassOps
     561             : };
     562             : 
     563             : // Class representing ctypes.CData.prototype and the 'prototype' properties
     564             : // of CTypes. This exists to give said prototypes a class of "CData".
     565             : static const JSClass sCDataProtoClass = {
     566             :   "CData",
     567             :   0
     568             : };
     569             : 
     570             : static const JSClassOps sCTypeClassOps = {
     571             :   nullptr, nullptr, nullptr, nullptr,
     572             :   nullptr, nullptr, nullptr, nullptr,
     573             :   CType::Finalize, CType::ConstructData, CType::HasInstance, CType::ConstructData,
     574             :   CType::Trace
     575             : };
     576             : static const JSClass sCTypeClass = {
     577             :   "CType",
     578             :   JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS) |
     579             :   JSCLASS_FOREGROUND_FINALIZE,
     580             :   &sCTypeClassOps
     581             : };
     582             : 
     583             : static const JSClassOps sCDataClassOps = {
     584             :   nullptr, nullptr, ArrayType::Getter, ArrayType::Setter,
     585             :   nullptr, nullptr, nullptr, nullptr,
     586             :   CData::Finalize, FunctionType::Call, nullptr, FunctionType::Call
     587             : };
     588             : static const JSClass sCDataClass = {
     589             :   "CData",
     590             :   JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS) |
     591             :   JSCLASS_FOREGROUND_FINALIZE,
     592             :   &sCDataClassOps
     593             : };
     594             : 
     595             : static const JSClassOps sCClosureClassOps = {
     596             :   nullptr, nullptr, nullptr, nullptr,
     597             :   nullptr, nullptr, nullptr, nullptr,
     598             :   CClosure::Finalize, nullptr, nullptr, nullptr,
     599             :   CClosure::Trace
     600             : };
     601             : static const JSClass sCClosureClass = {
     602             :   "CClosure",
     603             :   JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS) |
     604             :   JSCLASS_FOREGROUND_FINALIZE,
     605             :   &sCClosureClassOps
     606             : };
     607             : 
     608             : /*
     609             :  * Class representing the prototype of CDataFinalizer.
     610             :  */
     611             : static const JSClass sCDataFinalizerProtoClass = {
     612             :   "CDataFinalizer",
     613             :   0
     614             : };
     615             : 
     616             : /*
     617             :  * Class representing instances of CDataFinalizer.
     618             :  *
     619             :  * Instances of CDataFinalizer have both private data (with type
     620             :  * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|).
     621             :  */
     622             : static const JSClassOps sCDataFinalizerClassOps = {
     623             :   nullptr, nullptr, nullptr, nullptr,
     624             :   nullptr, nullptr, nullptr, nullptr,
     625             :   CDataFinalizer::Finalize
     626             : };
     627             : static const JSClass sCDataFinalizerClass = {
     628             :   "CDataFinalizer",
     629             :   JSCLASS_HAS_PRIVATE |
     630             :   JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS) |
     631             :   JSCLASS_FOREGROUND_FINALIZE,
     632             :   &sCDataFinalizerClassOps
     633             : };
     634             : 
     635             : 
     636             : #define CTYPESFN_FLAGS \
     637             :   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
     638             : 
     639             : #define CTYPESCTOR_FLAGS \
     640             :   (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR)
     641             : 
     642             : #define CTYPESACC_FLAGS \
     643             :   (JSPROP_ENUMERATE | JSPROP_PERMANENT)
     644             : 
     645             : #define CABIFN_FLAGS \
     646             :   (JSPROP_READONLY | JSPROP_PERMANENT)
     647             : 
     648             : #define CDATAFN_FLAGS \
     649             :   (JSPROP_READONLY | JSPROP_PERMANENT)
     650             : 
     651             : #define CDATAFINALIZERFN_FLAGS \
     652             :   (JSPROP_READONLY | JSPROP_PERMANENT)
     653             : 
     654             : static const JSPropertySpec sCTypeProps[] = {
     655             :   JS_PSG("name",
     656             :          (Property<CType::IsCType, CType::NameGetter>::Fun),
     657             :          CTYPESACC_FLAGS),
     658             :   JS_PSG("size",
     659             :          (Property<CType::IsCType, CType::SizeGetter>::Fun),
     660             :          CTYPESACC_FLAGS),
     661             :   JS_PSG("ptr",
     662             :          (Property<CType::IsCType, CType::PtrGetter>::Fun),
     663             :          CTYPESACC_FLAGS),
     664             :   JS_PSG("prototype",
     665             :          (Property<CType::IsCTypeOrProto, CType::PrototypeGetter>::Fun),
     666             :          CTYPESACC_FLAGS),
     667             :   JS_PS_END
     668             : };
     669             : 
     670             : static const JSFunctionSpec sCTypeFunctions[] = {
     671             :   JS_FN("array", CType::CreateArray, 0, CTYPESFN_FLAGS),
     672             :   JS_FN("toString", CType::ToString, 0, CTYPESFN_FLAGS),
     673             :   JS_FN("toSource", CType::ToSource, 0, CTYPESFN_FLAGS),
     674             :   JS_FS_END
     675             : };
     676             : 
     677             : static const JSFunctionSpec sCABIFunctions[] = {
     678             :   JS_FN("toSource", ABI::ToSource, 0, CABIFN_FLAGS),
     679             :   JS_FN("toString", ABI::ToSource, 0, CABIFN_FLAGS),
     680             :   JS_FS_END
     681             : };
     682             : 
     683             : static const JSPropertySpec sCDataProps[] = {
     684             :   JS_PSGS("value",
     685             :           (Property<CData::IsCData, CData::ValueGetter>::Fun),
     686             :           (Property<CData::IsCData, CData::ValueSetter>::Fun),
     687             :           JSPROP_PERMANENT),
     688             :   JS_PS_END
     689             : };
     690             : 
     691             : static const JSFunctionSpec sCDataFunctions[] = {
     692             :   JS_FN("address", CData::Address, 0, CDATAFN_FLAGS),
     693             :   JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS),
     694             :   JS_FN("readStringReplaceMalformed", CData::ReadStringReplaceMalformed, 0, CDATAFN_FLAGS),
     695             :   JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS),
     696             :   JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS),
     697             :   JS_FS_END
     698             : };
     699             : 
     700             : static const JSFunctionSpec sCDataFinalizerFunctions[] = {
     701             :   JS_FN("dispose",  CDataFinalizer::Methods::Dispose,  0, CDATAFINALIZERFN_FLAGS),
     702             :   JS_FN("forget",   CDataFinalizer::Methods::Forget,   0, CDATAFINALIZERFN_FLAGS),
     703             :   JS_FN("readString", CDataFinalizer::Methods::ReadString, 0, CDATAFINALIZERFN_FLAGS),
     704             :   JS_FN("toString", CDataFinalizer::Methods::ToString, 0, CDATAFINALIZERFN_FLAGS),
     705             :   JS_FN("toSource", CDataFinalizer::Methods::ToSource, 0, CDATAFINALIZERFN_FLAGS),
     706             :   JS_FS_END
     707             : };
     708             : 
     709             : static const JSFunctionSpec sPointerFunction =
     710             :   JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS);
     711             : 
     712             : static const JSPropertySpec sPointerProps[] = {
     713             :   JS_PSG("targetType",
     714             :          (Property<PointerType::IsPointerType, PointerType::TargetTypeGetter>::Fun),
     715             :          CTYPESACC_FLAGS),
     716             :   JS_PS_END
     717             : };
     718             : 
     719             : static const JSFunctionSpec sPointerInstanceFunctions[] = {
     720             :   JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS),
     721             :   JS_FN("increment", PointerType::Increment, 0, CTYPESFN_FLAGS),
     722             :   JS_FN("decrement", PointerType::Decrement, 0, CTYPESFN_FLAGS),
     723             :   JS_FS_END
     724             : };
     725             : 
     726             : static const JSPropertySpec sPointerInstanceProps[] = {
     727             :   JS_PSGS("contents",
     728             :          (Property<PointerType::IsPointer, PointerType::ContentsGetter>::Fun),
     729             :          (Property<PointerType::IsPointer, PointerType::ContentsSetter>::Fun),
     730             :           JSPROP_PERMANENT),
     731             :   JS_PS_END
     732             : };
     733             : 
     734             : static const JSFunctionSpec sArrayFunction =
     735             :   JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS);
     736             : 
     737             : static const JSPropertySpec sArrayProps[] = {
     738             :   JS_PSG("elementType",
     739             :          (Property<ArrayType::IsArrayType, ArrayType::ElementTypeGetter>::Fun),
     740             :          CTYPESACC_FLAGS),
     741             :   JS_PSG("length",
     742             :          (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
     743             :          CTYPESACC_FLAGS),
     744             :   JS_PS_END
     745             : };
     746             : 
     747             : static const JSFunctionSpec sArrayInstanceFunctions[] = {
     748             :   JS_FN("addressOfElement", ArrayType::AddressOfElement, 1, CDATAFN_FLAGS),
     749             :   JS_FS_END
     750             : };
     751             : 
     752             : static const JSPropertySpec sArrayInstanceProps[] = {
     753             :   JS_PSG("length",
     754             :          (Property<ArrayType::IsArrayOrArrayType, ArrayType::LengthGetter>::Fun),
     755             :          JSPROP_PERMANENT),
     756             :   JS_PS_END
     757             : };
     758             : 
     759             : static const JSFunctionSpec sStructFunction =
     760             :   JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS);
     761             : 
     762             : static const JSPropertySpec sStructProps[] = {
     763             :   JS_PSG("fields",
     764             :          (Property<StructType::IsStruct, StructType::FieldsArrayGetter>::Fun),
     765             :          CTYPESACC_FLAGS),
     766             :   JS_PS_END
     767             : };
     768             : 
     769             : static const JSFunctionSpec sStructFunctions[] = {
     770             :   JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS),
     771             :   JS_FS_END
     772             : };
     773             : 
     774             : static const JSFunctionSpec sStructInstanceFunctions[] = {
     775             :   JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS),
     776             :   JS_FS_END
     777             : };
     778             : 
     779             : static const JSFunctionSpec sFunctionFunction =
     780             :   JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS);
     781             : 
     782             : static const JSPropertySpec sFunctionProps[] = {
     783             :   JS_PSG("argTypes",
     784             :          (Property<FunctionType::IsFunctionType, FunctionType::ArgTypesGetter>::Fun),
     785             :          CTYPESACC_FLAGS),
     786             :   JS_PSG("returnType",
     787             :          (Property<FunctionType::IsFunctionType, FunctionType::ReturnTypeGetter>::Fun),
     788             :          CTYPESACC_FLAGS),
     789             :   JS_PSG("abi",
     790             :          (Property<FunctionType::IsFunctionType, FunctionType::ABIGetter>::Fun),
     791             :          CTYPESACC_FLAGS),
     792             :   JS_PSG("isVariadic",
     793             :          (Property<FunctionType::IsFunctionType, FunctionType::IsVariadicGetter>::Fun),
     794             :          CTYPESACC_FLAGS),
     795             :   JS_PS_END
     796             : };
     797             : 
     798             : static const JSFunctionSpec sFunctionInstanceFunctions[] = {
     799             :   JS_FN("call", js::fun_call, 1, CDATAFN_FLAGS),
     800             :   JS_FN("apply", js::fun_apply, 2, CDATAFN_FLAGS),
     801             :   JS_FS_END
     802             : };
     803             : 
     804             : static const JSClass sInt64ProtoClass = {
     805             :   "Int64",
     806             :   0
     807             : };
     808             : 
     809             : static const JSClass sUInt64ProtoClass = {
     810             :   "UInt64",
     811             :   0
     812             : };
     813             : 
     814             : static const JSClassOps sInt64ClassOps = {
     815             :   nullptr, nullptr, nullptr, nullptr,
     816             :   nullptr, nullptr, nullptr, nullptr,
     817             :   Int64Base::Finalize
     818             : };
     819             : 
     820             : static const JSClass sInt64Class = {
     821             :   "Int64",
     822             :   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS) |
     823             :   JSCLASS_FOREGROUND_FINALIZE,
     824             :   &sInt64ClassOps
     825             : };
     826             : 
     827             : static const JSClass sUInt64Class = {
     828             :   "UInt64",
     829             :   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS) |
     830             :   JSCLASS_FOREGROUND_FINALIZE,
     831             :   &sInt64ClassOps
     832             : };
     833             : 
     834             : static const JSFunctionSpec sInt64StaticFunctions[] = {
     835             :   JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS),
     836             :   JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS),
     837             :   JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS),
     838             :   // "join" is defined specially; see InitInt64Class.
     839             :   JS_FS_END
     840             : };
     841             : 
     842             : static const JSFunctionSpec sUInt64StaticFunctions[] = {
     843             :   JS_FN("compare", UInt64::Compare, 2, CTYPESFN_FLAGS),
     844             :   JS_FN("lo", UInt64::Lo, 1, CTYPESFN_FLAGS),
     845             :   JS_FN("hi", UInt64::Hi, 1, CTYPESFN_FLAGS),
     846             :   // "join" is defined specially; see InitInt64Class.
     847             :   JS_FS_END
     848             : };
     849             : 
     850             : static const JSFunctionSpec sInt64Functions[] = {
     851             :   JS_FN("toString", Int64::ToString, 0, CTYPESFN_FLAGS),
     852             :   JS_FN("toSource", Int64::ToSource, 0, CTYPESFN_FLAGS),
     853             :   JS_FS_END
     854             : };
     855             : 
     856             : static const JSFunctionSpec sUInt64Functions[] = {
     857             :   JS_FN("toString", UInt64::ToString, 0, CTYPESFN_FLAGS),
     858             :   JS_FN("toSource", UInt64::ToSource, 0, CTYPESFN_FLAGS),
     859             :   JS_FS_END
     860             : };
     861             : 
     862             : static const JSPropertySpec sModuleProps[] = {
     863             :   JS_PSG("errno",
     864             :          (Property<IsCTypesGlobal, CData::ErrnoGetter>::Fun),
     865             :          JSPROP_PERMANENT),
     866             : #if defined(XP_WIN)
     867             :   JS_PSG("winLastError",
     868             :          (Property<IsCTypesGlobal, CData::LastErrorGetter>::Fun),
     869             :          JSPROP_PERMANENT),
     870             : #endif // defined(XP_WIN)
     871             :   JS_PS_END
     872             : };
     873             : 
     874             : static const JSFunctionSpec sModuleFunctions[] = {
     875             :   JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS),
     876             :   JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
     877             :   JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
     878             :   JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
     879             :   JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
     880             :   JS_FS_END
     881             : };
     882             : 
     883             : static MOZ_ALWAYS_INLINE JSString*
     884           0 : NewUCString(JSContext* cx, const AutoString& from)
     885             : {
     886           0 :   return JS_NewUCStringCopyN(cx, from.begin(), from.length());
     887             : }
     888             : 
     889             : /*
     890             :  * Return a size rounded up to a multiple of a power of two.
     891             :  *
     892             :  * Note: |align| must be a power of 2.
     893             :  */
     894             : static MOZ_ALWAYS_INLINE size_t
     895           0 : Align(size_t val, size_t align)
     896             : {
     897             :   // Ensure that align is a power of two.
     898           0 :   MOZ_ASSERT(align != 0 && (align & (align - 1)) == 0);
     899           0 :   return ((val - 1) | (align - 1)) + 1;
     900             : }
     901             : 
     902             : static ABICode
     903           0 : GetABICode(JSObject* obj)
     904             : {
     905             :   // make sure we have an object representing a CABI class,
     906             :   // and extract the enumerated class type from the reserved slot.
     907           0 :   if (JS_GetClass(obj) != &sCABIClass)
     908           0 :     return INVALID_ABI;
     909             : 
     910           0 :   Value result = JS_GetReservedSlot(obj, SLOT_ABICODE);
     911           0 :   return ABICode(result.toInt32());
     912             : }
     913             : 
     914             : static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
     915             : #define MSG_DEF(name, count, exception, format) \
     916             :   { #name, format, count, exception } ,
     917             : #include "ctypes/ctypes.msg"
     918             : #undef MSG_DEF
     919             : };
     920             : 
     921             : static const JSErrorFormatString*
     922           0 : GetErrorMessage(void* userRef, const unsigned errorNumber)
     923             : {
     924           0 :   if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
     925           0 :     return &ErrorFormatString[errorNumber];
     926           0 :   return nullptr;
     927             : }
     928             : 
     929             : static const char*
     930           0 : EncodeLatin1(JSContext* cx, AutoString& str, JSAutoByteString& bytes)
     931             : {
     932           0 :   return bytes.encodeLatin1(cx, NewUCString(cx, str));
     933             : }
     934             : 
     935             : static const char*
     936           0 : CTypesToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes)
     937             : {
     938           0 :   if (val.isObject() &&
     939           0 :       (CType::IsCType(&val.toObject()) || CData::IsCData(&val.toObject()))) {
     940           0 :     RootedString str(cx, JS_ValueToSource(cx, val));
     941           0 :     return bytes.encodeLatin1(cx, str);
     942             :   }
     943           0 :   return ValueToSourceForError(cx, val, bytes);
     944             : }
     945             : 
     946             : static void
     947             : BuildCStyleFunctionTypeSource(JSContext* cx, HandleObject typeObj,
     948             :                               HandleString nameStr, unsigned ptrCount,
     949             :                               AutoString& source);
     950             : 
     951             : static void
     952           0 : BuildCStyleTypeSource(JSContext* cx, JSObject* typeObj_, AutoString& source)
     953             : {
     954           0 :   RootedObject typeObj(cx, typeObj_);
     955             : 
     956           0 :   MOZ_ASSERT(CType::IsCType(typeObj));
     957             : 
     958           0 :   switch (CType::GetTypeCode(typeObj)) {
     959             : #define BUILD_SOURCE(name, fromType, ffiType)                                  \
     960             :   case TYPE_##name:                                                            \
     961             :     AppendString(source, #name);                                               \
     962             :     break;
     963           0 :   CTYPES_FOR_EACH_TYPE(BUILD_SOURCE)
     964             : #undef BUILD_SOURCE
     965             :   case TYPE_void_t:
     966           0 :     AppendString(source, "void");
     967           0 :     break;
     968             :   case TYPE_pointer: {
     969           0 :     unsigned ptrCount = 0;
     970             :     TypeCode type;
     971           0 :     RootedObject baseTypeObj(cx, typeObj);
     972           0 :     do {
     973           0 :       baseTypeObj = PointerType::GetBaseType(baseTypeObj);
     974           0 :       ptrCount++;
     975           0 :       type = CType::GetTypeCode(baseTypeObj);
     976           0 :     } while (type == TYPE_pointer || type == TYPE_array);
     977           0 :     if (type == TYPE_function) {
     978           0 :       BuildCStyleFunctionTypeSource(cx, baseTypeObj, nullptr, ptrCount,
     979           0 :                                     source);
     980           0 :       break;
     981             :     }
     982           0 :     BuildCStyleTypeSource(cx, baseTypeObj, source);
     983           0 :     AppendChars(source, '*', ptrCount);
     984           0 :     break;
     985             :   }
     986             :   case TYPE_struct: {
     987           0 :     RootedString name(cx, CType::GetName(cx, typeObj));
     988           0 :     AppendString(source, "struct ");
     989           0 :     AppendString(source, name);
     990           0 :     break;
     991             :   }
     992             :   case TYPE_function:
     993           0 :     BuildCStyleFunctionTypeSource(cx, typeObj, nullptr, 0, source);
     994           0 :     break;
     995             :   case TYPE_array:
     996           0 :     MOZ_CRASH("TYPE_array shouldn't appear in function type");
     997             :   }
     998           0 : }
     999             : 
    1000             : static void
    1001           0 : BuildCStyleFunctionTypeSource(JSContext* cx, HandleObject typeObj,
    1002             :                               HandleString nameStr, unsigned ptrCount,
    1003             :                               AutoString& source)
    1004             : {
    1005           0 :   MOZ_ASSERT(CType::IsCType(typeObj));
    1006             : 
    1007           0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    1008           0 :   BuildCStyleTypeSource(cx, fninfo->mReturnType, source);
    1009           0 :   AppendString(source, " ");
    1010           0 :   if (nameStr) {
    1011           0 :     MOZ_ASSERT(ptrCount == 0);
    1012           0 :     AppendString(source, nameStr);
    1013           0 :   } else if (ptrCount) {
    1014           0 :     AppendString(source, "(");
    1015           0 :     AppendChars(source, '*', ptrCount);
    1016           0 :     AppendString(source, ")");
    1017             :   }
    1018           0 :   AppendString(source, "(");
    1019           0 :   if (fninfo->mArgTypes.length() > 0) {
    1020           0 :     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    1021           0 :       BuildCStyleTypeSource(cx, fninfo->mArgTypes[i], source);
    1022           0 :       if (i != fninfo->mArgTypes.length() - 1 || fninfo->mIsVariadic) {
    1023           0 :           AppendString(source, ", ");
    1024             :       }
    1025             :     }
    1026           0 :     if (fninfo->mIsVariadic) {
    1027           0 :       AppendString(source, "...");
    1028             :     }
    1029             :   }
    1030           0 :   AppendString(source, ")");
    1031           0 : }
    1032             : 
    1033             : static void
    1034           0 : BuildFunctionTypeSource(JSContext* cx, HandleObject funObj, AutoString& source)
    1035             : {
    1036           0 :   MOZ_ASSERT(CData::IsCData(funObj) || CType::IsCType(funObj));
    1037             : 
    1038           0 :   if (CData::IsCData(funObj)) {
    1039           0 :     Value slot = JS_GetReservedSlot(funObj, SLOT_REFERENT);
    1040           0 :     if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
    1041           0 :       slot = JS_GetReservedSlot(funObj, SLOT_FUNNAME);
    1042           0 :       MOZ_ASSERT(!slot.isUndefined());
    1043           0 :       RootedObject typeObj(cx, CData::GetCType(funObj));
    1044           0 :       RootedObject baseTypeObj(cx, PointerType::GetBaseType(typeObj));
    1045           0 :       RootedString nameStr(cx, slot.toString());
    1046           0 :       BuildCStyleFunctionTypeSource(cx, baseTypeObj, nameStr, 0, source);
    1047           0 :       return;
    1048             :     }
    1049             :   }
    1050             : 
    1051           0 :   RootedValue funVal(cx, ObjectValue(*funObj));
    1052           0 :   RootedString funcStr(cx, JS_ValueToSource(cx, funVal));
    1053           0 :   if (!funcStr) {
    1054           0 :     JS_ClearPendingException(cx);
    1055           0 :     AppendString(source, "<<error converting function to string>>");
    1056           0 :     return;
    1057             :   }
    1058           0 :   AppendString(source, funcStr);
    1059             : }
    1060             : 
    1061             : enum class ConversionType {
    1062             :   Argument = 0,
    1063             :   Construct,
    1064             :   Finalizer,
    1065             :   Return,
    1066             :   Setter
    1067             : };
    1068             : 
    1069             : static void
    1070           0 : BuildConversionPosition(JSContext* cx, ConversionType convType,
    1071             :                         HandleObject funObj, unsigned argIndex,
    1072             :                         AutoString& source)
    1073             : {
    1074           0 :   switch (convType) {
    1075             :   case ConversionType::Argument: {
    1076           0 :     MOZ_ASSERT(funObj);
    1077             : 
    1078           0 :     AppendString(source, " at argument ");
    1079           0 :     AppendUInt(source, argIndex + 1);
    1080           0 :     AppendString(source, " of ");
    1081           0 :     BuildFunctionTypeSource(cx, funObj, source);
    1082           0 :     break;
    1083             :   }
    1084             :   case ConversionType::Finalizer:
    1085           0 :     MOZ_ASSERT(funObj);
    1086             : 
    1087           0 :     AppendString(source, " at argument 1 of ");
    1088           0 :     BuildFunctionTypeSource(cx, funObj, source);
    1089           0 :     break;
    1090             :   case ConversionType::Return:
    1091           0 :     MOZ_ASSERT(funObj);
    1092             : 
    1093           0 :     AppendString(source, " at the return value of ");
    1094           0 :     BuildFunctionTypeSource(cx, funObj, source);
    1095           0 :     break;
    1096             :   default:
    1097           0 :     MOZ_ASSERT(!funObj);
    1098           0 :     break;
    1099             :   }
    1100           0 : }
    1101             : 
    1102             : static JSFlatString*
    1103           0 : GetFieldName(HandleObject structObj, unsigned fieldIndex)
    1104             : {
    1105           0 :   const FieldInfoHash* fields = StructType::GetFieldInfo(structObj);
    1106           0 :   for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    1107           0 :     if (r.front().value().mIndex == fieldIndex) {
    1108           0 :       return (&r.front())->key();
    1109             :     }
    1110             :   }
    1111           0 :   return nullptr;
    1112             : }
    1113             : 
    1114             : static void
    1115             : BuildTypeSource(JSContext* cx, JSObject* typeObj_, bool makeShort,
    1116             :                 AutoString& result);
    1117             : 
    1118             : static bool
    1119           0 : ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
    1120             :           ConversionType convType,
    1121             :           HandleObject funObj = nullptr, unsigned argIndex = 0,
    1122             :           HandleObject arrObj = nullptr, unsigned arrIndex = 0)
    1123             : {
    1124           0 :   JSAutoByteString valBytes;
    1125           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1126           0 :   if (!valStr)
    1127           0 :     return false;
    1128             : 
    1129           0 :   if (arrObj) {
    1130           0 :     MOZ_ASSERT(CType::IsCType(arrObj));
    1131             : 
    1132           0 :     switch (CType::GetTypeCode(arrObj)) {
    1133             :     case TYPE_array: {
    1134           0 :       MOZ_ASSERT(!funObj);
    1135             : 
    1136             :       char indexStr[16];
    1137           0 :       SprintfLiteral(indexStr, "%u", arrIndex);
    1138             : 
    1139           0 :       AutoString arrSource;
    1140           0 :       JSAutoByteString arrBytes;
    1141           0 :       BuildTypeSource(cx, arrObj, true, arrSource);
    1142           0 :       const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
    1143           0 :       if (!arrStr)
    1144           0 :         return false;
    1145             : 
    1146             :       JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1147             :                                  CTYPESMSG_CONV_ERROR_ARRAY,
    1148           0 :                                  valStr, indexStr, arrStr);
    1149           0 :       break;
    1150             :     }
    1151             :     case TYPE_struct: {
    1152           0 :       JSFlatString* name = GetFieldName(arrObj, arrIndex);
    1153           0 :       MOZ_ASSERT(name);
    1154           0 :       JSAutoByteString nameBytes;
    1155           0 :       const char* nameStr = nameBytes.encodeLatin1(cx, name);
    1156           0 :       if (!nameStr)
    1157           0 :         return false;
    1158             : 
    1159           0 :       AutoString structSource;
    1160           0 :       JSAutoByteString structBytes;
    1161           0 :       BuildTypeSource(cx, arrObj, true, structSource);
    1162           0 :       const char* structStr = EncodeLatin1(cx, structSource, structBytes);
    1163           0 :       if (!structStr)
    1164           0 :         return false;
    1165             : 
    1166           0 :       JSAutoByteString posBytes;
    1167             :       const char* posStr;
    1168           0 :       if (funObj) {
    1169           0 :         AutoString posSource;
    1170           0 :         BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
    1171           0 :         posStr = EncodeLatin1(cx, posSource, posBytes);
    1172           0 :         if (!posStr)
    1173           0 :           return false;
    1174             :       } else {
    1175           0 :         posStr = "";
    1176             :       }
    1177             : 
    1178             :       JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1179             :                                  CTYPESMSG_CONV_ERROR_STRUCT,
    1180           0 :                                  valStr, nameStr, expectedStr, structStr, posStr);
    1181           0 :       break;
    1182             :     }
    1183             :     default:
    1184           0 :       MOZ_CRASH("invalid arrObj value");
    1185             :     }
    1186           0 :     return false;
    1187             :   }
    1188             : 
    1189           0 :   switch (convType) {
    1190             :   case ConversionType::Argument: {
    1191           0 :     MOZ_ASSERT(funObj);
    1192             : 
    1193             :     char indexStr[16];
    1194           0 :     SprintfLiteral(indexStr, "%u", argIndex + 1);
    1195             : 
    1196           0 :     AutoString funSource;
    1197           0 :     JSAutoByteString funBytes;
    1198           0 :     BuildFunctionTypeSource(cx, funObj, funSource);
    1199           0 :     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
    1200           0 :     if (!funStr)
    1201           0 :       return false;
    1202             : 
    1203             :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1204             :                                CTYPESMSG_CONV_ERROR_ARG,
    1205           0 :                                valStr, indexStr, funStr);
    1206           0 :     break;
    1207             :   }
    1208             :   case ConversionType::Finalizer: {
    1209           0 :     MOZ_ASSERT(funObj);
    1210             : 
    1211           0 :     AutoString funSource;
    1212           0 :     JSAutoByteString funBytes;
    1213           0 :     BuildFunctionTypeSource(cx, funObj, funSource);
    1214           0 :     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
    1215           0 :     if (!funStr)
    1216           0 :       return false;
    1217             : 
    1218             :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1219           0 :                                CTYPESMSG_CONV_ERROR_FIN, valStr, funStr);
    1220           0 :     break;
    1221             :   }
    1222             :   case ConversionType::Return: {
    1223           0 :     MOZ_ASSERT(funObj);
    1224             : 
    1225           0 :     AutoString funSource;
    1226           0 :     JSAutoByteString funBytes;
    1227           0 :     BuildFunctionTypeSource(cx, funObj, funSource);
    1228           0 :     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
    1229           0 :     if (!funStr)
    1230           0 :       return false;
    1231             : 
    1232             :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1233           0 :                                CTYPESMSG_CONV_ERROR_RET, valStr, funStr);
    1234           0 :     break;
    1235             :   }
    1236             :   case ConversionType::Setter:
    1237             :   case ConversionType::Construct:
    1238           0 :     MOZ_ASSERT(!funObj);
    1239             : 
    1240             :     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1241           0 :                                CTYPESMSG_CONV_ERROR_SET, valStr, expectedStr);
    1242           0 :     break;
    1243             :   }
    1244             : 
    1245           0 :   return false;
    1246             : }
    1247             : 
    1248             : static bool
    1249           0 : ConvError(JSContext* cx, HandleObject expectedType, HandleValue actual,
    1250             :           ConversionType convType,
    1251             :           HandleObject funObj = nullptr, unsigned argIndex = 0,
    1252             :           HandleObject arrObj = nullptr, unsigned arrIndex = 0)
    1253             : {
    1254           0 :   MOZ_ASSERT(CType::IsCType(expectedType));
    1255             : 
    1256           0 :   AutoString expectedSource;
    1257           0 :   JSAutoByteString expectedBytes;
    1258           0 :   BuildTypeSource(cx, expectedType, true, expectedSource);
    1259           0 :   const char* expectedStr = EncodeLatin1(cx, expectedSource, expectedBytes);
    1260           0 :   if (!expectedStr)
    1261           0 :     return false;
    1262             : 
    1263             :   return ConvError(cx, expectedStr, actual, convType, funObj, argIndex,
    1264           0 :                    arrObj, arrIndex);
    1265             : }
    1266             : 
    1267             : static bool
    1268           0 : ArgumentConvError(JSContext* cx, HandleValue actual, const char* funStr,
    1269             :                   unsigned argIndex)
    1270             : {
    1271           0 :   JSAutoByteString valBytes;
    1272           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1273           0 :   if (!valStr)
    1274           0 :     return false;
    1275             : 
    1276             :   char indexStr[16];
    1277           0 :   SprintfLiteral(indexStr, "%u", argIndex + 1);
    1278             : 
    1279             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1280           0 :                              CTYPESMSG_CONV_ERROR_ARG, valStr, indexStr, funStr);
    1281           0 :   return false;
    1282             : }
    1283             : 
    1284             : static bool
    1285           0 : ArgumentLengthError(JSContext* cx, const char* fun, const char* count,
    1286             :                     const char* s)
    1287             : {
    1288             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1289           0 :                              CTYPESMSG_WRONG_ARG_LENGTH, fun, count, s);
    1290           0 :   return false;
    1291             : }
    1292             : 
    1293             : static bool
    1294           0 : ArrayLengthMismatch(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
    1295             :                     unsigned actualLength, HandleValue actual,
    1296             :                     ConversionType convType)
    1297             : {
    1298           0 :   MOZ_ASSERT(arrObj && CType::IsCType(arrObj));
    1299             : 
    1300           0 :   JSAutoByteString valBytes;
    1301           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1302           0 :   if (!valStr)
    1303           0 :     return false;
    1304             : 
    1305             :   char expectedLengthStr[16];
    1306           0 :   SprintfLiteral(expectedLengthStr, "%u", expectedLength);
    1307             :   char actualLengthStr[16];
    1308           0 :   SprintfLiteral(actualLengthStr, "%u", actualLength);
    1309             : 
    1310           0 :   AutoString arrSource;
    1311           0 :   JSAutoByteString arrBytes;
    1312           0 :   BuildTypeSource(cx, arrObj, true, arrSource);
    1313           0 :   const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
    1314           0 :   if (!arrStr)
    1315           0 :     return false;
    1316             : 
    1317             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1318             :                              CTYPESMSG_ARRAY_MISMATCH,
    1319           0 :                              valStr, arrStr, expectedLengthStr, actualLengthStr);
    1320           0 :   return false;
    1321             : }
    1322             : 
    1323             : static bool
    1324           0 : ArrayLengthOverflow(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
    1325             :                     unsigned actualLength, HandleValue actual,
    1326             :                     ConversionType convType)
    1327             : {
    1328           0 :   MOZ_ASSERT(arrObj && CType::IsCType(arrObj));
    1329             : 
    1330           0 :   JSAutoByteString valBytes;
    1331           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1332           0 :   if (!valStr)
    1333           0 :     return false;
    1334             : 
    1335             :   char expectedLengthStr[16];
    1336           0 :   SprintfLiteral(expectedLengthStr, "%u", expectedLength);
    1337             :   char actualLengthStr[16];
    1338           0 :   SprintfLiteral(actualLengthStr, "%u", actualLength);
    1339             : 
    1340           0 :   AutoString arrSource;
    1341           0 :   JSAutoByteString arrBytes;
    1342           0 :   BuildTypeSource(cx, arrObj, true, arrSource);
    1343           0 :   const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
    1344           0 :   if (!arrStr)
    1345           0 :     return false;
    1346             : 
    1347             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1348             :                              CTYPESMSG_ARRAY_OVERFLOW,
    1349           0 :                              valStr, arrStr, expectedLengthStr, actualLengthStr);
    1350           0 :   return false;
    1351             : }
    1352             : 
    1353             : static bool
    1354           0 : ArgumentRangeMismatch(JSContext* cx, const char* func, const char* range)
    1355             : {
    1356             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1357           0 :                             CTYPESMSG_ARG_RANGE_MISMATCH, func, range);
    1358           0 :   return false;
    1359             : }
    1360             : 
    1361             : static bool
    1362           0 : ArgumentTypeMismatch(JSContext* cx, const char* arg, const char* func,
    1363             :                      const char* type)
    1364             : {
    1365             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1366           0 :                             CTYPESMSG_ARG_TYPE_MISMATCH, arg, func, type);
    1367           0 :   return false;
    1368             : }
    1369             : 
    1370             : static bool
    1371           0 : CannotConstructError(JSContext* cx, const char* type)
    1372             : {
    1373             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1374           0 :                             CTYPESMSG_CANNOT_CONSTRUCT, type);
    1375           0 :   return false;
    1376             : }
    1377             : 
    1378             : static bool
    1379           0 : DuplicateFieldError(JSContext* cx, Handle<JSFlatString*> name)
    1380             : {
    1381           0 :   JSAutoByteString nameBytes;
    1382           0 :   const char* nameStr = nameBytes.encodeLatin1(cx, name);
    1383           0 :   if (!nameStr)
    1384           0 :     return false;
    1385             : 
    1386             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1387           0 :                              CTYPESMSG_DUPLICATE_FIELD, nameStr);
    1388           0 :   return false;
    1389             : }
    1390             : 
    1391             : static bool
    1392           0 : EmptyFinalizerCallError(JSContext* cx, const char* funName)
    1393             : {
    1394             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1395           0 :                             CTYPESMSG_EMPTY_FIN_CALL, funName);
    1396           0 :   return false;
    1397             : }
    1398             : 
    1399             : static bool
    1400           0 : EmptyFinalizerError(JSContext* cx, ConversionType convType,
    1401             :                     HandleObject funObj = nullptr, unsigned argIndex = 0)
    1402             : {
    1403           0 :   JSAutoByteString posBytes;
    1404             :   const char* posStr;
    1405           0 :   if (funObj) {
    1406           0 :     AutoString posSource;
    1407           0 :     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
    1408           0 :     posStr = EncodeLatin1(cx, posSource, posBytes);
    1409           0 :     if (!posStr)
    1410           0 :       return false;
    1411             :   } else {
    1412           0 :     posStr = "";
    1413             :   }
    1414             : 
    1415             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1416           0 :                              CTYPESMSG_EMPTY_FIN, posStr);
    1417           0 :   return false;
    1418             : }
    1419             : 
    1420             : static bool
    1421           0 : FieldCountMismatch(JSContext* cx,
    1422             :                    unsigned expectedCount, HandleObject structObj,
    1423             :                    unsigned actualCount, HandleValue actual,
    1424             :                    ConversionType convType,
    1425             :                    HandleObject funObj = nullptr, unsigned argIndex = 0)
    1426             : {
    1427           0 :   MOZ_ASSERT(structObj && CType::IsCType(structObj));
    1428             : 
    1429           0 :   JSAutoByteString valBytes;
    1430           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1431           0 :   if (!valStr)
    1432           0 :     return false;
    1433             : 
    1434           0 :   AutoString structSource;
    1435           0 :   JSAutoByteString structBytes;
    1436           0 :   BuildTypeSource(cx, structObj, true, structSource);
    1437           0 :   const char* structStr = EncodeLatin1(cx, structSource, structBytes);
    1438           0 :   if (!structStr)
    1439           0 :     return false;
    1440             : 
    1441             :   char expectedCountStr[16];
    1442           0 :   SprintfLiteral(expectedCountStr, "%u", expectedCount);
    1443             :   char actualCountStr[16];
    1444           0 :   SprintfLiteral(actualCountStr, "%u", actualCount);
    1445             : 
    1446           0 :   JSAutoByteString posBytes;
    1447             :   const char* posStr;
    1448           0 :   if (funObj) {
    1449           0 :     AutoString posSource;
    1450           0 :     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
    1451           0 :     posStr = EncodeLatin1(cx, posSource, posBytes);
    1452           0 :     if (!posStr)
    1453           0 :       return false;
    1454             :   } else {
    1455           0 :     posStr = "";
    1456             :   }
    1457             : 
    1458             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1459             :                              CTYPESMSG_FIELD_MISMATCH,
    1460             :                              valStr, structStr, expectedCountStr, actualCountStr,
    1461           0 :                              posStr);
    1462           0 :   return false;
    1463             : }
    1464             : 
    1465             : static bool
    1466           0 : FieldDescriptorCountError(JSContext* cx, HandleValue typeVal, size_t length)
    1467             : {
    1468           0 :   JSAutoByteString valBytes;
    1469           0 :   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
    1470           0 :   if (!valStr)
    1471           0 :     return false;
    1472             : 
    1473             :   char lengthStr[16];
    1474           0 :   SprintfLiteral(lengthStr, "%" PRIuSIZE, length);
    1475             : 
    1476             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1477           0 :                              CTYPESMSG_FIELD_DESC_COUNT, valStr, lengthStr);
    1478           0 :   return false;
    1479             : }
    1480             : 
    1481             : static bool
    1482           0 : FieldDescriptorNameError(JSContext* cx, HandleId id)
    1483             : {
    1484           0 :   JSAutoByteString idBytes;
    1485           0 :   RootedValue idVal(cx, IdToValue(id));
    1486           0 :   const char* propStr = CTypesToSourceForError(cx, idVal, idBytes);
    1487           0 :   if (!propStr)
    1488           0 :     return false;
    1489             : 
    1490             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1491           0 :                              CTYPESMSG_FIELD_DESC_NAME, propStr);
    1492           0 :   return false;
    1493             : }
    1494             : 
    1495             : static bool
    1496           0 : FieldDescriptorSizeError(JSContext* cx, HandleObject typeObj, HandleId id)
    1497             : {
    1498           0 :   RootedValue typeVal(cx, ObjectValue(*typeObj));
    1499           0 :   JSAutoByteString typeBytes;
    1500           0 :   const char* typeStr = CTypesToSourceForError(cx, typeVal, typeBytes);
    1501           0 :   if (!typeStr)
    1502           0 :     return false;
    1503             : 
    1504           0 :   RootedString idStr(cx, IdToString(cx, id));
    1505           0 :   JSAutoByteString idBytes;
    1506           0 :   const char* propStr = idBytes.encodeLatin1(cx, idStr);
    1507           0 :   if (!propStr)
    1508           0 :     return false;
    1509             : 
    1510             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1511           0 :                              CTYPESMSG_FIELD_DESC_SIZE, typeStr, propStr);
    1512           0 :   return false;
    1513             : }
    1514             : 
    1515             : static bool
    1516           0 : FieldDescriptorNameTypeError(JSContext* cx, HandleValue typeVal)
    1517             : {
    1518           0 :   JSAutoByteString valBytes;
    1519           0 :   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
    1520           0 :   if (!valStr)
    1521           0 :     return false;
    1522             : 
    1523             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1524           0 :                              CTYPESMSG_FIELD_DESC_NAMETYPE, valStr);
    1525           0 :   return false;
    1526             : }
    1527             : 
    1528             : static bool
    1529           0 : FieldDescriptorTypeError(JSContext* cx, HandleValue poroVal, HandleId id)
    1530             : {
    1531           0 :   JSAutoByteString typeBytes;
    1532           0 :   const char* typeStr = CTypesToSourceForError(cx, poroVal, typeBytes);
    1533           0 :   if (!typeStr)
    1534           0 :     return false;
    1535             : 
    1536           0 :   RootedString idStr(cx, IdToString(cx, id));
    1537           0 :   JSAutoByteString idBytes;
    1538           0 :   const char* propStr = idBytes.encodeLatin1(cx, idStr);
    1539           0 :   if (!propStr)
    1540           0 :     return false;
    1541             : 
    1542             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1543           0 :                              CTYPESMSG_FIELD_DESC_TYPE, typeStr, propStr);
    1544           0 :   return false;
    1545             : }
    1546             : 
    1547             : static bool
    1548           0 : FieldMissingError(JSContext* cx, JSObject* typeObj, JSFlatString* name_)
    1549             : {
    1550           0 :   JSAutoByteString typeBytes;
    1551           0 :   RootedString name(cx, name_);
    1552           0 :   RootedValue typeVal(cx, ObjectValue(*typeObj));
    1553           0 :   const char* typeStr = CTypesToSourceForError(cx, typeVal, typeBytes);
    1554           0 :   if (!typeStr)
    1555           0 :     return false;
    1556             : 
    1557           0 :   JSAutoByteString nameBytes;
    1558           0 :   const char* nameStr = nameBytes.encodeLatin1(cx, name);
    1559           0 :   if (!nameStr)
    1560           0 :     return false;
    1561             : 
    1562             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1563           0 :                              CTYPESMSG_FIELD_MISSING, typeStr, nameStr);
    1564           0 :   return false;
    1565             : }
    1566             : 
    1567             : static bool
    1568           0 : FinalizerSizeError(JSContext* cx, HandleObject funObj, HandleValue actual)
    1569             : {
    1570           0 :   MOZ_ASSERT(CType::IsCType(funObj));
    1571             : 
    1572           0 :   JSAutoByteString valBytes;
    1573           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1574           0 :   if (!valStr)
    1575           0 :     return false;
    1576             : 
    1577           0 :   AutoString funSource;
    1578           0 :   JSAutoByteString funBytes;
    1579           0 :   BuildFunctionTypeSource(cx, funObj, funSource);
    1580           0 :   const char* funStr = EncodeLatin1(cx, funSource, funBytes);
    1581           0 :   if (!funStr)
    1582           0 :     return false;
    1583             : 
    1584             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1585           0 :                              CTYPESMSG_FIN_SIZE_ERROR, funStr, valStr);
    1586           0 :   return false;
    1587             : }
    1588             : 
    1589             : static bool
    1590           0 : FunctionArgumentLengthMismatch(JSContext* cx,
    1591             :                                unsigned expectedCount, unsigned actualCount,
    1592             :                                HandleObject funObj, HandleObject typeObj,
    1593             :                                bool isVariadic)
    1594             : {
    1595           0 :   AutoString funSource;
    1596           0 :   JSAutoByteString funBytes;
    1597           0 :   Value slot = JS_GetReservedSlot(funObj, SLOT_REFERENT);
    1598           0 :   if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
    1599           0 :     BuildFunctionTypeSource(cx, funObj, funSource);
    1600             :   } else {
    1601           0 :     BuildFunctionTypeSource(cx, typeObj, funSource);
    1602             :   }
    1603           0 :   const char* funStr = EncodeLatin1(cx, funSource, funBytes);
    1604           0 :   if (!funStr)
    1605           0 :     return false;
    1606             : 
    1607             :   char expectedCountStr[16];
    1608           0 :   SprintfLiteral(expectedCountStr, "%u", expectedCount);
    1609             :   char actualCountStr[16];
    1610           0 :   SprintfLiteral(actualCountStr, "%u", actualCount);
    1611             : 
    1612           0 :   const char* variadicStr = isVariadic ? " or more": "";
    1613             : 
    1614             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1615             :                              CTYPESMSG_ARG_COUNT_MISMATCH,
    1616             :                              funStr, expectedCountStr, variadicStr,
    1617           0 :                              actualCountStr);
    1618           0 :   return false;
    1619             : }
    1620             : 
    1621             : static bool
    1622           0 : FunctionArgumentTypeError(JSContext* cx,
    1623             :                           uint32_t index, HandleValue typeVal, const char* reason)
    1624             : {
    1625           0 :   JSAutoByteString valBytes;
    1626           0 :   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
    1627           0 :   if (!valStr)
    1628           0 :     return false;
    1629             : 
    1630             :   char indexStr[16];
    1631           0 :   SprintfLiteral(indexStr, "%u", index + 1);
    1632             : 
    1633             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1634             :                              CTYPESMSG_ARG_TYPE_ERROR,
    1635           0 :                              indexStr, reason, valStr);
    1636           0 :   return false;
    1637             : }
    1638             : 
    1639             : static bool
    1640           0 : FunctionReturnTypeError(JSContext* cx, HandleValue type, const char* reason)
    1641             : {
    1642           0 :   JSAutoByteString valBytes;
    1643           0 :   const char* valStr = CTypesToSourceForError(cx, type, valBytes);
    1644           0 :   if (!valStr)
    1645           0 :     return false;
    1646             : 
    1647             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1648           0 :                              CTYPESMSG_RET_TYPE_ERROR, reason, valStr);
    1649           0 :   return false;
    1650             : }
    1651             : 
    1652             : static bool
    1653           0 : IncompatibleCallee(JSContext* cx, const char* funName, HandleObject actualObj)
    1654             : {
    1655           0 :   JSAutoByteString valBytes;
    1656           0 :   RootedValue val(cx, ObjectValue(*actualObj));
    1657           0 :   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
    1658           0 :   if (!valStr)
    1659           0 :     return false;
    1660             : 
    1661             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1662           0 :                              CTYPESMSG_INCOMPATIBLE_CALLEE, funName, valStr);
    1663           0 :   return false;
    1664             : }
    1665             : 
    1666             : static bool
    1667           0 : IncompatibleThisProto(JSContext* cx, const char* funName,
    1668             :                       const char* actualType)
    1669             : {
    1670             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1671             :                              CTYPESMSG_INCOMPATIBLE_THIS,
    1672           0 :                              funName, actualType);
    1673           0 :   return false;
    1674             : }
    1675             : 
    1676             : static bool
    1677           0 : IncompatibleThisProto(JSContext* cx, const char* funName, HandleValue actualVal)
    1678             : {
    1679           0 :   JSAutoByteString valBytes;
    1680           0 :   const char* valStr = CTypesToSourceForError(cx, actualVal, valBytes);
    1681           0 :   if (!valStr)
    1682           0 :     return false;
    1683             : 
    1684             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1685             :                              CTYPESMSG_INCOMPATIBLE_THIS_VAL,
    1686           0 :                              funName, "incompatible object", valStr);
    1687           0 :   return false;
    1688             : }
    1689             : 
    1690             : static bool
    1691           0 : IncompatibleThisType(JSContext* cx, const char* funName, const char* actualType)
    1692             : {
    1693             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1694             :                             CTYPESMSG_INCOMPATIBLE_THIS_TYPE,
    1695           0 :                             funName, actualType);
    1696           0 :   return false;
    1697             : }
    1698             : 
    1699             : static bool
    1700           0 : IncompatibleThisType(JSContext* cx, const char* funName, const char* actualType,
    1701             :                      HandleValue actualVal)
    1702             : {
    1703           0 :   JSAutoByteString valBytes;
    1704           0 :   const char* valStr = CTypesToSourceForError(cx, actualVal, valBytes);
    1705           0 :   if (!valStr)
    1706           0 :     return false;
    1707             : 
    1708             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1709             :                              CTYPESMSG_INCOMPATIBLE_THIS_VAL,
    1710           0 :                              funName, actualType, valStr);
    1711           0 :   return false;
    1712             : }
    1713             : 
    1714             : static bool
    1715           0 : InvalidIndexError(JSContext* cx, HandleValue val)
    1716             : {
    1717           0 :   JSAutoByteString idBytes;
    1718           0 :   const char* indexStr = CTypesToSourceForError(cx, val, idBytes);
    1719           0 :   if (!indexStr)
    1720           0 :     return false;
    1721             : 
    1722             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1723           0 :                              CTYPESMSG_INVALID_INDEX, indexStr);
    1724           0 :   return false;
    1725             : }
    1726             : 
    1727             : static bool
    1728           0 : InvalidIndexError(JSContext* cx, HandleId id)
    1729             : {
    1730           0 :   RootedValue idVal(cx, IdToValue(id));
    1731           0 :   return InvalidIndexError(cx, idVal);
    1732             : }
    1733             : 
    1734             : static bool
    1735           0 : InvalidIndexRangeError(JSContext* cx, size_t index, size_t length)
    1736             : {
    1737             :   char indexStr[16];
    1738           0 :   SprintfLiteral(indexStr, "%" PRIuSIZE, index);
    1739             : 
    1740             :   char lengthStr[16];
    1741           0 :   SprintfLiteral(lengthStr,"%" PRIuSIZE, length);
    1742             : 
    1743             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1744           0 :                             CTYPESMSG_INVALID_RANGE, indexStr, lengthStr);
    1745           0 :   return false;
    1746             : }
    1747             : 
    1748             : static bool
    1749           0 : NonPrimitiveError(JSContext* cx, HandleObject typeObj)
    1750             : {
    1751           0 :   MOZ_ASSERT(CType::IsCType(typeObj));
    1752             : 
    1753           0 :   AutoString typeSource;
    1754           0 :   JSAutoByteString typeBytes;
    1755           0 :   BuildTypeSource(cx, typeObj, true, typeSource);
    1756           0 :   const char* typeStr = EncodeLatin1(cx, typeSource, typeBytes);
    1757           0 :   if (!typeStr)
    1758           0 :     return false;
    1759             : 
    1760             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1761           0 :                              CTYPESMSG_NON_PRIMITIVE, typeStr);
    1762           0 :   return false;
    1763             : }
    1764             : 
    1765             : static bool
    1766           0 : NonStringBaseError(JSContext* cx, HandleValue thisVal)
    1767             : {
    1768           0 :   JSAutoByteString valBytes;
    1769           0 :   const char* valStr = CTypesToSourceForError(cx, thisVal, valBytes);
    1770           0 :   if (!valStr)
    1771           0 :     return false;
    1772             : 
    1773             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1774           0 :                              CTYPESMSG_NON_STRING_BASE, valStr);
    1775           0 :   return false;
    1776             : }
    1777             : 
    1778             : static bool
    1779           0 : NullPointerError(JSContext* cx, const char* action, HandleObject obj)
    1780             : {
    1781           0 :   JSAutoByteString valBytes;
    1782           0 :   RootedValue val(cx, ObjectValue(*obj));
    1783           0 :   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
    1784           0 :   if (!valStr)
    1785           0 :     return false;
    1786             : 
    1787             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1788           0 :                              CTYPESMSG_NULL_POINTER, action, valStr);
    1789           0 :   return false;
    1790             : }
    1791             : 
    1792             : static bool
    1793           0 : PropNameNonStringError(JSContext* cx, HandleId id, HandleValue actual,
    1794             :                        ConversionType convType,
    1795             :                        HandleObject funObj = nullptr, unsigned argIndex = 0)
    1796             : {
    1797           0 :   JSAutoByteString valBytes;
    1798           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1799           0 :   if (!valStr)
    1800           0 :     return false;
    1801             : 
    1802           0 :   JSAutoByteString idBytes;
    1803           0 :   RootedValue idVal(cx, IdToValue(id));
    1804           0 :   const char* propStr = CTypesToSourceForError(cx, idVal, idBytes);
    1805           0 :   if (!propStr)
    1806           0 :     return false;
    1807             : 
    1808           0 :   JSAutoByteString posBytes;
    1809             :   const char* posStr;
    1810           0 :   if (funObj) {
    1811           0 :     AutoString posSource;
    1812           0 :     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
    1813           0 :     posStr = EncodeLatin1(cx, posSource, posBytes);
    1814           0 :     if (!posStr)
    1815           0 :       return false;
    1816             :   } else {
    1817           0 :     posStr = "";
    1818             :   }
    1819             : 
    1820             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1821           0 :                              CTYPESMSG_PROP_NONSTRING, propStr, valStr, posStr);
    1822           0 :   return false;
    1823             : }
    1824             : 
    1825             : static bool
    1826           0 : SizeOverflow(JSContext* cx, const char* name, const char* limit)
    1827             : {
    1828             :   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1829           0 :                             CTYPESMSG_SIZE_OVERFLOW, name, limit);
    1830           0 :   return false;
    1831             : }
    1832             : 
    1833             : static bool
    1834           0 : TypeError(JSContext* cx, const char* expected, HandleValue actual)
    1835             : {
    1836           0 :   JSAutoByteString bytes;
    1837           0 :   const char* src = CTypesToSourceForError(cx, actual, bytes);
    1838           0 :   if (!src)
    1839           0 :     return false;
    1840             : 
    1841             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1842           0 :                              CTYPESMSG_TYPE_ERROR, expected, src);
    1843           0 :   return false;
    1844             : }
    1845             : 
    1846             : static bool
    1847           0 : TypeOverflow(JSContext* cx, const char* expected, HandleValue actual)
    1848             : {
    1849           0 :   JSAutoByteString valBytes;
    1850           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1851           0 :   if (!valStr)
    1852           0 :     return false;
    1853             : 
    1854             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1855           0 :                              CTYPESMSG_TYPE_OVERFLOW, valStr, expected);
    1856           0 :   return false;
    1857             : }
    1858             : 
    1859             : static bool
    1860           0 : UndefinedSizeCastError(JSContext* cx, HandleObject targetTypeObj)
    1861             : {
    1862           0 :   AutoString targetTypeSource;
    1863           0 :   JSAutoByteString targetTypeBytes;
    1864           0 :   BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
    1865             :   const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
    1866           0 :                                            targetTypeBytes);
    1867           0 :   if (!targetTypeStr)
    1868           0 :     return false;
    1869             : 
    1870             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1871           0 :                              CTYPESMSG_UNDEFINED_SIZE_CAST, targetTypeStr);
    1872           0 :   return false;
    1873             : }
    1874             : 
    1875             : static bool
    1876           0 : SizeMismatchCastError(JSContext* cx,
    1877             :                       HandleObject sourceTypeObj, HandleObject targetTypeObj,
    1878             :                       size_t sourceSize, size_t targetSize)
    1879             : {
    1880           0 :   AutoString sourceTypeSource;
    1881           0 :   JSAutoByteString sourceTypeBytes;
    1882           0 :   BuildTypeSource(cx, sourceTypeObj, true, sourceTypeSource);
    1883             :   const char* sourceTypeStr = EncodeLatin1(cx, sourceTypeSource,
    1884           0 :                                            sourceTypeBytes);
    1885           0 :   if (!sourceTypeStr)
    1886           0 :     return false;
    1887             : 
    1888           0 :   AutoString targetTypeSource;
    1889           0 :   JSAutoByteString targetTypeBytes;
    1890           0 :   BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
    1891             :   const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
    1892           0 :                                            targetTypeBytes);
    1893           0 :   if (!targetTypeStr)
    1894           0 :     return false;
    1895             : 
    1896             :   char sourceSizeStr[16];
    1897             :   char targetSizeStr[16];
    1898           0 :   SprintfLiteral(sourceSizeStr, "%" PRIuSIZE, sourceSize);
    1899           0 :   SprintfLiteral(targetSizeStr, "%" PRIuSIZE, targetSize);
    1900             : 
    1901             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1902             :                              CTYPESMSG_SIZE_MISMATCH_CAST,
    1903             :                              targetTypeStr, sourceTypeStr,
    1904           0 :                              targetSizeStr, sourceSizeStr);
    1905           0 :   return false;
    1906             : }
    1907             : 
    1908             : static bool
    1909           0 : UndefinedSizePointerError(JSContext* cx, const char* action, HandleObject obj)
    1910             : {
    1911           0 :   JSAutoByteString valBytes;
    1912           0 :   RootedValue val(cx, ObjectValue(*obj));
    1913           0 :   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
    1914           0 :   if (!valStr)
    1915           0 :     return false;
    1916             : 
    1917             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1918           0 :                              CTYPESMSG_UNDEFINED_SIZE, action, valStr);
    1919           0 :   return false;
    1920             : }
    1921             : 
    1922             : static bool
    1923           0 : VariadicArgumentTypeError(JSContext* cx, uint32_t index, HandleValue actual)
    1924             : {
    1925           0 :   JSAutoByteString valBytes;
    1926           0 :   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
    1927           0 :   if (!valStr)
    1928           0 :     return false;
    1929             : 
    1930             :   char indexStr[16];
    1931           0 :   SprintfLiteral(indexStr, "%u", index + 1);
    1932             : 
    1933             :   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    1934           0 :                              CTYPESMSG_VARG_TYPE_ERROR, indexStr, valStr);
    1935           0 :   return false;
    1936             : }
    1937             : 
    1938             : static JSObject*
    1939           2 : InitCTypeClass(JSContext* cx, HandleObject ctypesObj)
    1940             : {
    1941           2 :   JSFunction* fun = JS_DefineFunction(cx, ctypesObj, "CType", ConstructAbstract, 0,
    1942           2 :                                       CTYPESCTOR_FLAGS);
    1943           2 :   if (!fun)
    1944           0 :     return nullptr;
    1945             : 
    1946           4 :   RootedObject ctor(cx, JS_GetFunctionObject(fun));
    1947           4 :   RootedObject fnproto(cx);
    1948           2 :   if (!JS_GetPrototype(cx, ctor, &fnproto))
    1949           0 :     return nullptr;
    1950           2 :   MOZ_ASSERT(ctor);
    1951           2 :   MOZ_ASSERT(fnproto);
    1952             : 
    1953             :   // Set up ctypes.CType.prototype.
    1954           4 :   RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, fnproto));
    1955           2 :   if (!prototype)
    1956           0 :     return nullptr;
    1957             : 
    1958           2 :   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
    1959             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    1960           0 :     return nullptr;
    1961             : 
    1962           2 :   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
    1963             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    1964           0 :     return nullptr;
    1965             : 
    1966             :   // Define properties and functions common to all CTypes.
    1967           8 :   if (!JS_DefineProperties(cx, prototype, sCTypeProps) ||
    1968           6 :       !JS_DefineFunctions(cx, prototype, sCTypeFunctions))
    1969           0 :     return nullptr;
    1970             : 
    1971           2 :   if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
    1972           0 :     return nullptr;
    1973             : 
    1974           2 :   return prototype;
    1975             : }
    1976             : 
    1977             : static JSObject*
    1978           2 : InitABIClass(JSContext* cx)
    1979             : {
    1980           4 :   RootedObject obj(cx, JS_NewPlainObject(cx));
    1981             : 
    1982           2 :   if (!obj)
    1983           0 :     return nullptr;
    1984             : 
    1985           2 :   if (!JS_DefineFunctions(cx, obj, sCABIFunctions))
    1986           0 :     return nullptr;
    1987             : 
    1988           2 :   return obj;
    1989             : }
    1990             : 
    1991             : 
    1992             : static JSObject*
    1993           2 : InitCDataClass(JSContext* cx, HandleObject parent, HandleObject CTypeProto)
    1994             : {
    1995           2 :   JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0,
    1996           2 :                       CTYPESCTOR_FLAGS);
    1997           2 :   if (!fun)
    1998           0 :     return nullptr;
    1999             : 
    2000           4 :   RootedObject ctor(cx, JS_GetFunctionObject(fun));
    2001           2 :   MOZ_ASSERT(ctor);
    2002             : 
    2003             :   // Set up ctypes.CData.__proto__ === ctypes.CType.prototype.
    2004             :   // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the
    2005             :   // prototype chain.)
    2006           2 :   if (!JS_SetPrototype(cx, ctor, CTypeProto))
    2007           0 :     return nullptr;
    2008             : 
    2009             :   // Set up ctypes.CData.prototype.
    2010           4 :   RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass));
    2011           2 :   if (!prototype)
    2012           0 :     return nullptr;
    2013             : 
    2014           2 :   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
    2015             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2016           0 :     return nullptr;
    2017             : 
    2018           2 :   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
    2019             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2020           0 :     return nullptr;
    2021             : 
    2022             :   // Define properties and functions common to all CDatas.
    2023           8 :   if (!JS_DefineProperties(cx, prototype, sCDataProps) ||
    2024           6 :       !JS_DefineFunctions(cx, prototype, sCDataFunctions))
    2025           0 :     return nullptr;
    2026             : 
    2027           4 :   if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
    2028           4 :       !JS_FreezeObject(cx, ctor))
    2029           0 :     return nullptr;
    2030             : 
    2031           2 :   return prototype;
    2032             : }
    2033             : 
    2034             : static bool
    2035           8 : DefineABIConstant(JSContext* cx,
    2036             :                   HandleObject ctypesObj,
    2037             :                   const char* name,
    2038             :                   ABICode code,
    2039             :                   HandleObject prototype)
    2040             : {
    2041          16 :   RootedObject obj(cx, JS_NewObjectWithGivenProto(cx, &sCABIClass, prototype));
    2042           8 :   if (!obj)
    2043           0 :     return false;
    2044           8 :   JS_SetReservedSlot(obj, SLOT_ABICODE, Int32Value(code));
    2045             : 
    2046           8 :   if (!JS_FreezeObject(cx, obj))
    2047           0 :     return false;
    2048             : 
    2049          16 :   return JS_DefineProperty(cx, ctypesObj, name, obj,
    2050           8 :                            JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
    2051             : }
    2052             : 
    2053             : // Set up a single type constructor for
    2054             : // ctypes.{Pointer,Array,Struct,Function}Type.
    2055             : static bool
    2056           8 : InitTypeConstructor(JSContext* cx,
    2057             :                     HandleObject parent,
    2058             :                     HandleObject CTypeProto,
    2059             :                     HandleObject CDataProto,
    2060             :                     const JSFunctionSpec spec,
    2061             :                     const JSFunctionSpec* fns,
    2062             :                     const JSPropertySpec* props,
    2063             :                     const JSFunctionSpec* instanceFns,
    2064             :                     const JSPropertySpec* instanceProps,
    2065             :                     MutableHandleObject typeProto,
    2066             :                     MutableHandleObject dataProto)
    2067             : {
    2068          24 :   JSFunction* fun = js::DefineFunctionWithReserved(cx, parent, spec.name, spec.call.op,
    2069          32 :                       spec.nargs, spec.flags);
    2070           8 :   if (!fun)
    2071           0 :     return false;
    2072             : 
    2073          16 :   RootedObject obj(cx, JS_GetFunctionObject(fun));
    2074           8 :   if (!obj)
    2075           0 :     return false;
    2076             : 
    2077             :   // Set up the .prototype and .prototype.constructor properties.
    2078           8 :   typeProto.set(JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, CTypeProto));
    2079           8 :   if (!typeProto)
    2080           0 :     return false;
    2081             : 
    2082             :   // Define property before proceeding, for GC safety.
    2083           8 :   if (!JS_DefineProperty(cx, obj, "prototype", typeProto,
    2084             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2085           0 :     return false;
    2086             : 
    2087           8 :   if (fns && !JS_DefineFunctions(cx, typeProto, fns))
    2088           0 :     return false;
    2089             : 
    2090           8 :   if (!JS_DefineProperties(cx, typeProto, props))
    2091           0 :     return false;
    2092             : 
    2093           8 :   if (!JS_DefineProperty(cx, typeProto, "constructor", obj,
    2094             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2095           0 :     return false;
    2096             : 
    2097             :   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
    2098             :   // the type constructor, for faster lookup.
    2099           8 :   js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, ObjectValue(*typeProto));
    2100             : 
    2101             :   // Create an object to serve as the common ancestor for all CData objects
    2102             :   // created from the given type constructor. This has ctypes.CData.prototype
    2103             :   // as its prototype, such that it inherits the properties and functions
    2104             :   // common to all CDatas.
    2105           8 :   dataProto.set(JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, CDataProto));
    2106           8 :   if (!dataProto)
    2107           0 :     return false;
    2108             : 
    2109             :   // Define functions and properties on the 'dataProto' object that are common
    2110             :   // to all CData objects created from this type constructor. (These will
    2111             :   // become functions and properties on CData objects created from this type.)
    2112           8 :   if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns))
    2113           0 :     return false;
    2114             : 
    2115           8 :   if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps))
    2116           0 :     return false;
    2117             : 
    2118             :   // Link the type prototype to the data prototype.
    2119           8 :   JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, ObjectValue(*dataProto));
    2120             : 
    2121          32 :   if (!JS_FreezeObject(cx, obj) ||
    2122             :       //!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
    2123          24 :       !JS_FreezeObject(cx, typeProto))
    2124           0 :     return false;
    2125             : 
    2126           8 :   return true;
    2127             : }
    2128             : 
    2129             : static JSObject*
    2130           4 : InitInt64Class(JSContext* cx,
    2131             :                HandleObject parent,
    2132             :                const JSClass* clasp,
    2133             :                JSNative construct,
    2134             :                const JSFunctionSpec* fs,
    2135             :                const JSFunctionSpec* static_fs)
    2136             : {
    2137             :   // Init type class and constructor
    2138           8 :   RootedObject prototype(cx, JS_InitClass(cx, parent, nullptr, clasp, construct,
    2139           8 :                                           0, nullptr, fs, nullptr, static_fs));
    2140           4 :   if (!prototype)
    2141           0 :     return nullptr;
    2142             : 
    2143           8 :   RootedObject ctor(cx, JS_GetConstructor(cx, prototype));
    2144           4 :   if (!ctor)
    2145           0 :     return nullptr;
    2146             : 
    2147             :   // Define the 'join' function as an extended native and stash
    2148             :   // ctypes.{Int64,UInt64}.prototype in a reserved slot of the new function.
    2149           4 :   MOZ_ASSERT(clasp == &sInt64ProtoClass || clasp == &sUInt64ProtoClass);
    2150           4 :   JSNative native = (clasp == &sInt64ProtoClass) ? Int64::Join : UInt64::Join;
    2151           4 :   JSFunction* fun = js::DefineFunctionWithReserved(cx, ctor, "join", native,
    2152           8 :                       2, CTYPESFN_FLAGS);
    2153           4 :   if (!fun)
    2154           0 :     return nullptr;
    2155             : 
    2156           4 :   js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO, ObjectValue(*prototype));
    2157             : 
    2158           4 :   if (!JS_FreezeObject(cx, ctor))
    2159           0 :     return nullptr;
    2160           4 :   if (!JS_FreezeObject(cx, prototype))
    2161           0 :     return nullptr;
    2162             : 
    2163           4 :   return prototype;
    2164             : }
    2165             : 
    2166             : static void
    2167          10 : AttachProtos(JSObject* proto, const AutoObjectVector& protos)
    2168             : {
    2169             :   // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos'
    2170             :   // to the appropriate CTypeProtoSlot. (SLOT_CTYPES is the last slot
    2171             :   // of [[Class]] "CTypeProto" that we fill in this automated manner.)
    2172         130 :   for (uint32_t i = 0; i <= SLOT_CTYPES; ++i)
    2173         120 :     JS_SetReservedSlot(proto, i, ObjectOrNullValue(protos[i]));
    2174          10 : }
    2175             : 
    2176             : static bool
    2177           2 : InitTypeClasses(JSContext* cx, HandleObject ctypesObj)
    2178             : {
    2179             :   // Initialize the ctypes.CType class. This acts as an abstract base class for
    2180             :   // the various types, and provides the common API functions. It has:
    2181             :   //   * [[Class]] "Function"
    2182             :   //   * __proto__ === Function.prototype
    2183             :   //   * A constructor that throws a TypeError. (You can't construct an
    2184             :   //     abstract type!)
    2185             :   //   * 'prototype' property:
    2186             :   //     * [[Class]] "CTypeProto"
    2187             :   //     * __proto__ === Function.prototype
    2188             :   //     * A constructor that throws a TypeError. (You can't construct an
    2189             :   //       abstract type instance!)
    2190             :   //     * 'constructor' property === ctypes.CType
    2191             :   //     * Provides properties and functions common to all CTypes.
    2192           4 :   RootedObject CTypeProto(cx, InitCTypeClass(cx, ctypesObj));
    2193           2 :   if (!CTypeProto)
    2194           0 :     return false;
    2195             : 
    2196             :   // Initialize the ctypes.CData class. This acts as an abstract base class for
    2197             :   // instances of the various types, and provides the common API functions.
    2198             :   // It has:
    2199             :   //   * [[Class]] "Function"
    2200             :   //   * __proto__ === Function.prototype
    2201             :   //   * A constructor that throws a TypeError. (You can't construct an
    2202             :   //     abstract type instance!)
    2203             :   //   * 'prototype' property:
    2204             :   //     * [[Class]] "CDataProto"
    2205             :   //     * 'constructor' property === ctypes.CData
    2206             :   //     * Provides properties and functions common to all CDatas.
    2207           4 :   RootedObject CDataProto(cx, InitCDataClass(cx, ctypesObj, CTypeProto));
    2208           2 :   if (!CDataProto)
    2209           0 :     return false;
    2210             : 
    2211             :   // Link CTypeProto to CDataProto.
    2212           2 :   JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO, ObjectValue(*CDataProto));
    2213             : 
    2214             :   // Create and attach the special class constructors: ctypes.PointerType,
    2215             :   // ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType.
    2216             :   // Each of these constructors 'c' has, respectively:
    2217             :   //   * [[Class]] "Function"
    2218             :   //   * __proto__ === Function.prototype
    2219             :   //   * A constructor that creates a user-defined type.
    2220             :   //   * 'prototype' property:
    2221             :   //     * [[Class]] "CTypeProto"
    2222             :   //     * __proto__ === ctypes.CType.prototype
    2223             :   //     * 'constructor' property === 'c'
    2224             :   // We also construct an object 'p' to serve, given a type object 't'
    2225             :   // constructed from one of these type constructors, as
    2226             :   // 't.prototype.__proto__'. This object has:
    2227             :   //   * [[Class]] "CDataProto"
    2228             :   //   * __proto__ === ctypes.CData.prototype
    2229             :   //   * Properties and functions common to all CDatas.
    2230             :   // Therefore an instance 't' of ctypes.{Pointer,Array,Struct,Function}Type
    2231             :   // will have, resp.:
    2232             :   //   * [[Class]] "CType"
    2233             :   //   * __proto__ === ctypes.{Pointer,Array,Struct,Function}Type.prototype
    2234             :   //   * A constructor which creates and returns a CData object, containing
    2235             :   //     binary data of the given type.
    2236             :   //   * 'prototype' property:
    2237             :   //     * [[Class]] "CDataProto"
    2238             :   //     * __proto__ === 'p', the prototype object from above
    2239             :   //     * 'constructor' property === 't'
    2240           4 :   AutoObjectVector protos(cx);
    2241           2 :   if (!protos.resize(CTYPEPROTO_SLOTS))
    2242           0 :       return false;
    2243           2 :   if (!InitTypeConstructor(cx, ctypesObj, CTypeProto, CDataProto,
    2244             :          sPointerFunction, nullptr, sPointerProps,
    2245             :          sPointerInstanceFunctions, sPointerInstanceProps,
    2246             :          protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO]))
    2247           0 :     return false;
    2248             : 
    2249           2 :   if (!InitTypeConstructor(cx, ctypesObj, CTypeProto, CDataProto,
    2250             :          sArrayFunction, nullptr, sArrayProps,
    2251             :          sArrayInstanceFunctions, sArrayInstanceProps,
    2252             :          protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO]))
    2253           0 :     return false;
    2254             : 
    2255           2 :   if (!InitTypeConstructor(cx, ctypesObj, CTypeProto, CDataProto,
    2256             :          sStructFunction, sStructFunctions, sStructProps,
    2257             :          sStructInstanceFunctions, nullptr,
    2258             :          protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO]))
    2259           0 :     return false;
    2260             : 
    2261           2 :   if (!InitTypeConstructor(cx, ctypesObj, CTypeProto, protos[SLOT_POINTERDATAPROTO],
    2262             :          sFunctionFunction, nullptr, sFunctionProps, sFunctionInstanceFunctions, nullptr,
    2263             :          protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO]))
    2264           0 :     return false;
    2265             : 
    2266           2 :   protos[SLOT_CDATAPROTO].set(CDataProto);
    2267             : 
    2268             :   // Create and attach the ctypes.{Int64,UInt64} constructors.
    2269             :   // Each of these has, respectively:
    2270             :   //   * [[Class]] "Function"
    2271             :   //   * __proto__ === Function.prototype
    2272             :   //   * A constructor that creates a ctypes.{Int64,UInt64} object, respectively.
    2273             :   //   * 'prototype' property:
    2274             :   //     * [[Class]] {"Int64Proto","UInt64Proto"}
    2275             :   //     * 'constructor' property === ctypes.{Int64,UInt64}
    2276           4 :   protos[SLOT_INT64PROTO].set(InitInt64Class(cx, ctypesObj, &sInt64ProtoClass,
    2277           2 :     Int64::Construct, sInt64Functions, sInt64StaticFunctions));
    2278           2 :   if (!protos[SLOT_INT64PROTO])
    2279           0 :     return false;
    2280           4 :   protos[SLOT_UINT64PROTO].set(InitInt64Class(cx, ctypesObj, &sUInt64ProtoClass,
    2281           2 :     UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions));
    2282           2 :   if (!protos[SLOT_UINT64PROTO])
    2283           0 :     return false;
    2284             : 
    2285             :   // Finally, store a pointer to the global ctypes object.
    2286             :   // Note that there is no other reliable manner of locating this object.
    2287           2 :   protos[SLOT_CTYPES].set(ctypesObj);
    2288             : 
    2289             :   // Attach the prototypes just created to each of ctypes.CType.prototype,
    2290             :   // and the special type constructors, so we can access them when constructing
    2291             :   // instances of those types.
    2292           2 :   AttachProtos(CTypeProto, protos);
    2293           2 :   AttachProtos(protos[SLOT_POINTERPROTO], protos);
    2294           2 :   AttachProtos(protos[SLOT_ARRAYPROTO], protos);
    2295           2 :   AttachProtos(protos[SLOT_STRUCTPROTO], protos);
    2296           2 :   AttachProtos(protos[SLOT_FUNCTIONPROTO], protos);
    2297             : 
    2298           4 :   RootedObject ABIProto(cx, InitABIClass(cx));
    2299           2 :   if (!ABIProto)
    2300           0 :     return false;
    2301             : 
    2302             :   // Attach objects representing ABI constants.
    2303          12 :   if (!DefineABIConstant(cx, ctypesObj, "default_abi", ABI_DEFAULT, ABIProto) ||
    2304          10 :       !DefineABIConstant(cx, ctypesObj, "stdcall_abi", ABI_STDCALL, ABIProto) ||
    2305          16 :       !DefineABIConstant(cx, ctypesObj, "thiscall_abi", ABI_THISCALL, ABIProto) ||
    2306           6 :       !DefineABIConstant(cx, ctypesObj, "winapi_abi", ABI_WINAPI, ABIProto))
    2307           0 :     return false;
    2308             : 
    2309             :   // Create objects representing the builtin types, and attach them to the
    2310             :   // ctypes object. Each type object 't' has:
    2311             :   //   * [[Class]] "CType"
    2312             :   //   * __proto__ === ctypes.CType.prototype
    2313             :   //   * A constructor which creates and returns a CData object, containing
    2314             :   //     binary data of the given type.
    2315             :   //   * 'prototype' property:
    2316             :   //     * [[Class]] "CDataProto"
    2317             :   //     * __proto__ === ctypes.CData.prototype
    2318             :   //     * 'constructor' property === 't'
    2319             : #define DEFINE_TYPE(name, type, ffiType)                                       \
    2320             :   RootedObject typeObj_##name(cx);                                             \
    2321             :   {                                                                            \
    2322             :     RootedValue typeVal(cx, Int32Value(sizeof(type)));                         \
    2323             :     RootedValue alignVal(cx, Int32Value(ffiType.alignment));                   \
    2324             :     typeObj_##name = CType::DefineBuiltin(cx, ctypesObj, #name, CTypeProto,    \
    2325             :                                           CDataProto, #name, TYPE_##name,      \
    2326             :                                           typeVal, alignVal, &ffiType);        \
    2327             :     if (!typeObj_##name)                                                       \
    2328             :       return false;                                                            \
    2329             :   }
    2330           4 :   CTYPES_FOR_EACH_TYPE(DEFINE_TYPE)
    2331             : #undef DEFINE_TYPE
    2332             : 
    2333             :   // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
    2334             :   // the same type in C.
    2335           2 :   if (!JS_DefineProperty(cx, ctypesObj, "unsigned", typeObj_unsigned_int,
    2336             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2337           0 :     return false;
    2338             : 
    2339             :   // Alias 'ctypes.jschar' as 'ctypes.char16_t' to prevent breaking addons
    2340             :   // that are still using jschar (bug 1064935).
    2341           2 :   if (!JS_DefineProperty(cx, ctypesObj, "jschar", typeObj_char16_t,
    2342             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2343           0 :     return false;
    2344             : 
    2345             :   // Create objects representing the special types void_t and voidptr_t.
    2346             :   RootedObject typeObj(cx,
    2347           6 :     CType::DefineBuiltin(cx, ctypesObj, "void_t", CTypeProto, CDataProto, "void",
    2348             :                          TYPE_void_t, JS::UndefinedHandleValue, JS::UndefinedHandleValue,
    2349           8 :                          &ffi_type_void));
    2350           2 :   if (!typeObj)
    2351           0 :     return false;
    2352             : 
    2353           2 :   typeObj = PointerType::CreateInternal(cx, typeObj);
    2354           2 :   if (!typeObj)
    2355           0 :     return false;
    2356           2 :   if (!JS_DefineProperty(cx, ctypesObj, "voidptr_t", typeObj,
    2357             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2358           0 :     return false;
    2359             : 
    2360           2 :   return true;
    2361             : }
    2362             : 
    2363             : bool
    2364           2 : IsCTypesGlobal(JSObject* obj)
    2365             : {
    2366           2 :   return JS_GetClass(obj) == &sCTypesGlobalClass;
    2367             : }
    2368             : 
    2369             : bool
    2370           0 : IsCTypesGlobal(HandleValue v)
    2371             : {
    2372           0 :   return v.isObject() && IsCTypesGlobal(&v.toObject());
    2373             : }
    2374             : 
    2375             : // Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'.
    2376             : const JSCTypesCallbacks*
    2377           0 : GetCallbacks(JSObject* obj)
    2378             : {
    2379           0 :   MOZ_ASSERT(IsCTypesGlobal(obj));
    2380             : 
    2381           0 :   Value result = JS_GetReservedSlot(obj, SLOT_CALLBACKS);
    2382           0 :   if (result.isUndefined())
    2383           0 :     return nullptr;
    2384             : 
    2385           0 :   return static_cast<const JSCTypesCallbacks*>(result.toPrivate());
    2386             : }
    2387             : 
    2388             : // Utility function to access a property of an object as an object
    2389             : // returns false and sets the error if the property does not exist
    2390             : // or is not an object
    2391           2 : static bool GetObjectProperty(JSContext* cx, HandleObject obj,
    2392             :                               const char* property, MutableHandleObject result)
    2393             : {
    2394           4 :   RootedValue val(cx);
    2395           2 :   if (!JS_GetProperty(cx, obj, property, &val)) {
    2396           0 :     return false;
    2397             :   }
    2398             : 
    2399           2 :   if (val.isPrimitive()) {
    2400           0 :     JS_ReportErrorASCII(cx, "missing or non-object field");
    2401           0 :     return false;
    2402             :   }
    2403             : 
    2404           2 :   result.set(val.toObjectOrNull());
    2405           2 :   return true;
    2406             : }
    2407             : 
    2408             : } /* namespace ctypes */
    2409             : } /* namespace js */
    2410             : 
    2411             : using namespace js;
    2412             : using namespace js::ctypes;
    2413             : 
    2414             : JS_PUBLIC_API(bool)
    2415           2 : JS_InitCTypesClass(JSContext* cx, HandleObject global)
    2416             : {
    2417             :   // attach ctypes property to global object
    2418           4 :   RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass));
    2419           2 :   if (!ctypes)
    2420           0 :     return false;
    2421             : 
    2422           2 :   if (!JS_DefineProperty(cx, global, "ctypes", ctypes,
    2423             :                          JSPROP_READONLY | JSPROP_PERMANENT,
    2424             :                          JS_STUBGETTER, JS_STUBSETTER)){
    2425           0 :     return false;
    2426             :   }
    2427             : 
    2428           2 :   if (!InitTypeClasses(cx, ctypes))
    2429           0 :     return false;
    2430             : 
    2431             :   // attach API functions and properties
    2432           8 :   if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions) ||
    2433           6 :       !JS_DefineProperties(cx, ctypes, sModuleProps))
    2434           0 :     return false;
    2435             : 
    2436             :   // Set up ctypes.CDataFinalizer.prototype.
    2437           4 :   RootedObject ctor(cx);
    2438           2 :   if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor))
    2439           0 :     return false;
    2440             : 
    2441           4 :   RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass));
    2442           2 :   if (!prototype)
    2443           0 :     return false;
    2444             : 
    2445           2 :   if (!JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions))
    2446           0 :     return false;
    2447             : 
    2448           2 :   if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
    2449             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2450           0 :     return false;
    2451             : 
    2452           2 :   if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
    2453             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2454           0 :     return false;
    2455             : 
    2456             : 
    2457             :   // Seal the ctypes object, to prevent modification.
    2458           2 :   return JS_FreezeObject(cx, ctypes);
    2459             : }
    2460             : 
    2461             : JS_PUBLIC_API(void)
    2462           2 : JS_SetCTypesCallbacks(JSObject* ctypesObj, const JSCTypesCallbacks* callbacks)
    2463             : {
    2464           2 :   MOZ_ASSERT(callbacks);
    2465           2 :   MOZ_ASSERT(IsCTypesGlobal(ctypesObj));
    2466             : 
    2467             :   // Set the callbacks on a reserved slot.
    2468             :   JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS,
    2469           2 :                      PrivateValue(const_cast<JSCTypesCallbacks*>(callbacks)));
    2470           2 : }
    2471             : 
    2472             : namespace js {
    2473             : 
    2474             : JS_FRIEND_API(size_t)
    2475           0 : SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj)
    2476             : {
    2477           0 :     if (!CData::IsCData(obj))
    2478           0 :         return 0;
    2479             : 
    2480           0 :     size_t n = 0;
    2481           0 :     Value slot = JS_GetReservedSlot(obj, ctypes::SLOT_OWNS);
    2482           0 :     if (!slot.isUndefined()) {
    2483           0 :         bool owns = slot.toBoolean();
    2484           0 :         slot = JS_GetReservedSlot(obj, ctypes::SLOT_DATA);
    2485           0 :         if (!slot.isUndefined()) {
    2486           0 :             char** buffer = static_cast<char**>(slot.toPrivate());
    2487           0 :             n += mallocSizeOf(buffer);
    2488           0 :             if (owns)
    2489           0 :                 n += mallocSizeOf(*buffer);
    2490             :         }
    2491             :     }
    2492           0 :     return n;
    2493             : }
    2494             : 
    2495             : namespace ctypes {
    2496             : 
    2497             : /*******************************************************************************
    2498             : ** Type conversion functions
    2499             : *******************************************************************************/
    2500             : 
    2501             : // Enforce some sanity checks on type widths and properties.
    2502             : // Where the architecture is 64-bit, make sure it's LP64 or LLP64. (ctypes.int
    2503             : // autoconverts to a primitive JS number; to support ILP64 architectures, it
    2504             : // would need to autoconvert to an Int64 object instead. Therefore we enforce
    2505             : // this invariant here.)
    2506             : JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4);
    2507             : JS_STATIC_ASSERT(sizeof(char) == 1);
    2508             : JS_STATIC_ASSERT(sizeof(short) == 2);
    2509             : JS_STATIC_ASSERT(sizeof(int) == 4);
    2510             : JS_STATIC_ASSERT(sizeof(unsigned) == 4);
    2511             : JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
    2512             : JS_STATIC_ASSERT(sizeof(long long) == 8);
    2513             : JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
    2514             : JS_STATIC_ASSERT(sizeof(float) == 4);
    2515             : JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
    2516             : JS_STATIC_ASSERT(numeric_limits<double>::is_signed);
    2517             : 
    2518             : // Templated helper to convert FromType to TargetType, for the default case
    2519             : // where the trivial POD constructor will do.
    2520             : template<class TargetType, class FromType>
    2521             : struct ConvertImpl {
    2522           0 :   static MOZ_ALWAYS_INLINE TargetType Convert(FromType d) {
    2523           0 :     return TargetType(d);
    2524             :   }
    2525             : };
    2526             : 
    2527             : #ifdef _MSC_VER
    2528             : // MSVC can't perform double to unsigned __int64 conversion when the
    2529             : // double is greater than 2^63 - 1. Help it along a little.
    2530             : template<>
    2531             : struct ConvertImpl<uint64_t, double> {
    2532             :   static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
    2533             :     return d > 0x7fffffffffffffffui64 ?
    2534             :            uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
    2535             :            uint64_t(d);
    2536             :   }
    2537             : };
    2538             : #endif
    2539             : 
    2540             : // C++ doesn't guarantee that exact values are the only ones that will
    2541             : // round-trip. In fact, on some platforms, including SPARC, there are pairs of
    2542             : // values, a uint64_t and a double, such that neither value is exactly
    2543             : // representable in the other type, but they cast to each other.
    2544             : #if defined(SPARC) || defined(__powerpc__)
    2545             : // Simulate x86 overflow behavior
    2546             : template<>
    2547             : struct ConvertImpl<uint64_t, double> {
    2548             :   static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
    2549             :     return d >= 0xffffffffffffffff ?
    2550             :            0x8000000000000000 : uint64_t(d);
    2551             :   }
    2552             : };
    2553             : 
    2554             : template<>
    2555             : struct ConvertImpl<int64_t, double> {
    2556             :   static MOZ_ALWAYS_INLINE int64_t Convert(double d) {
    2557             :     return d >= 0x7fffffffffffffff ?
    2558             :            0x8000000000000000 : int64_t(d);
    2559             :   }
    2560             : };
    2561             : #endif
    2562             : 
    2563             : template<class TargetType, class FromType>
    2564           0 : static MOZ_ALWAYS_INLINE TargetType Convert(FromType d)
    2565             : {
    2566           0 :   return ConvertImpl<TargetType, FromType>::Convert(d);
    2567             : }
    2568             : 
    2569             : template<class TargetType, class FromType>
    2570           0 : static MOZ_ALWAYS_INLINE bool IsAlwaysExact()
    2571             : {
    2572             :   // Return 'true' if TargetType can always exactly represent FromType.
    2573             :   // This means that:
    2574             :   // 1) TargetType must be the same or more bits wide as FromType. For integers
    2575             :   //    represented in 'n' bits, unsigned variants will have 'n' digits while
    2576             :   //    signed will have 'n - 1'. For floating point types, 'digits' is the
    2577             :   //    mantissa width.
    2578             :   // 2) If FromType is signed, TargetType must also be signed. (Floating point
    2579             :   //    types are always signed.)
    2580             :   // 3) If TargetType is an exact integral type, FromType must be also.
    2581             :   if (numeric_limits<TargetType>::digits < numeric_limits<FromType>::digits)
    2582           0 :     return false;
    2583             : 
    2584             :   if (numeric_limits<FromType>::is_signed &&
    2585             :       !numeric_limits<TargetType>::is_signed)
    2586           0 :     return false;
    2587             : 
    2588             :   if (!numeric_limits<FromType>::is_exact &&
    2589             :       numeric_limits<TargetType>::is_exact)
    2590           0 :     return false;
    2591             : 
    2592           0 :   return true;
    2593             : }
    2594             : 
    2595             : // Templated helper to determine if FromType 'i' converts losslessly to
    2596             : // TargetType 'j'. Default case where both types are the same signedness.
    2597             : template<class TargetType, class FromType, bool TargetSigned, bool FromSigned>
    2598             : struct IsExactImpl {
    2599           0 :   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    2600             :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    2601           0 :     return FromType(j) == i;
    2602             :   }
    2603             : };
    2604             : 
    2605             : // Specialization where TargetType is unsigned, FromType is signed.
    2606             : template<class TargetType, class FromType>
    2607             : struct IsExactImpl<TargetType, FromType, false, true> {
    2608           0 :   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    2609             :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    2610           0 :     return i >= 0 && FromType(j) == i;
    2611             :   }
    2612             : };
    2613             : 
    2614             : // Specialization where TargetType is signed, FromType is unsigned.
    2615             : template<class TargetType, class FromType>
    2616             : struct IsExactImpl<TargetType, FromType, true, false> {
    2617           0 :   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    2618             :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    2619           0 :     return TargetType(i) >= 0 && FromType(j) == i;
    2620             :   }
    2621             : };
    2622             : 
    2623             : // Convert FromType 'i' to TargetType 'result', returning true iff 'result'
    2624             : // is an exact representation of 'i'.
    2625             : template<class TargetType, class FromType>
    2626           0 : static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
    2627             : {
    2628             :   // Require that TargetType is integral, to simplify conversion.
    2629             :   JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    2630             : 
    2631           0 :   *result = Convert<TargetType>(i);
    2632             : 
    2633             :   // See if we can avoid a dynamic check.
    2634           0 :   if (IsAlwaysExact<TargetType, FromType>())
    2635           0 :     return true;
    2636             : 
    2637             :   // Return 'true' if 'i' is exactly representable in 'TargetType'.
    2638             :   return IsExactImpl<TargetType,
    2639             :                      FromType,
    2640             :                      numeric_limits<TargetType>::is_signed,
    2641           0 :                      numeric_limits<FromType>::is_signed>::Test(i, *result);
    2642             : }
    2643             : 
    2644             : // Templated helper to determine if Type 'i' is negative. Default case
    2645             : // where IntegerType is unsigned.
    2646             : template<class Type, bool IsSigned>
    2647             : struct IsNegativeImpl {
    2648           0 :   static MOZ_ALWAYS_INLINE bool Test(Type i) {
    2649           0 :     return false;
    2650             :   }
    2651             : };
    2652             : 
    2653             : // Specialization where Type is signed.
    2654             : template<class Type>
    2655             : struct IsNegativeImpl<Type, true> {
    2656           0 :   static MOZ_ALWAYS_INLINE bool Test(Type i) {
    2657           0 :     return i < 0;
    2658             :   }
    2659             : };
    2660             : 
    2661             : // Determine whether Type 'i' is negative.
    2662             : template<class Type>
    2663           0 : static MOZ_ALWAYS_INLINE bool IsNegative(Type i)
    2664             : {
    2665           0 :   return IsNegativeImpl<Type, numeric_limits<Type>::is_signed>::Test(i);
    2666             : }
    2667             : 
    2668             : // Implicitly convert val to bool, allowing bool, int, and double
    2669             : // arguments numerically equal to 0 or 1.
    2670             : static bool
    2671           0 : jsvalToBool(JSContext* cx, HandleValue val, bool* result)
    2672             : {
    2673           0 :   if (val.isBoolean()) {
    2674           0 :     *result = val.toBoolean();
    2675           0 :     return true;
    2676             :   }
    2677           0 :   if (val.isInt32()) {
    2678           0 :     int32_t i = val.toInt32();
    2679           0 :     *result = i != 0;
    2680           0 :     return i == 0 || i == 1;
    2681             :   }
    2682           0 :   if (val.isDouble()) {
    2683           0 :     double d = val.toDouble();
    2684           0 :     *result = d != 0;
    2685             :     // Allow -0.
    2686           0 :     return d == 1 || d == 0;
    2687             :   }
    2688             :   // Don't silently convert null to bool. It's probably a mistake.
    2689           0 :   return false;
    2690             : }
    2691             : 
    2692             : // Implicitly convert val to IntegerType, allowing bool, int, double,
    2693             : // Int64, UInt64, and CData integer types 't' where all values of 't' are
    2694             : // representable by IntegerType.
    2695             : template<class IntegerType>
    2696             : static bool
    2697           0 : jsvalToInteger(JSContext* cx, HandleValue val, IntegerType* result)
    2698             : {
    2699             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    2700             : 
    2701           0 :   if (val.isInt32()) {
    2702             :     // Make sure the integer fits in the alotted precision, and has the right
    2703             :     // sign.
    2704           0 :     int32_t i = val.toInt32();
    2705           0 :     return ConvertExact(i, result);
    2706             :   }
    2707           0 :   if (val.isDouble()) {
    2708             :     // Don't silently lose bits here -- check that val really is an
    2709             :     // integer value, and has the right sign.
    2710           0 :     double d = val.toDouble();
    2711           0 :     return ConvertExact(d, result);
    2712             :   }
    2713           0 :   if (val.isObject()) {
    2714           0 :     JSObject* obj = &val.toObject();
    2715           0 :     if (CData::IsCData(obj)) {
    2716           0 :       JSObject* typeObj = CData::GetCType(obj);
    2717           0 :       void* data = CData::GetData(obj);
    2718             : 
    2719             :       // Check whether the source type is always representable, with exact
    2720             :       // precision, by the target type. If it is, convert the value.
    2721           0 :       switch (CType::GetTypeCode(typeObj)) {
    2722             : #define INTEGER_CASE(name, fromType, ffiType)                                  \
    2723             :       case TYPE_##name:                                                        \
    2724             :         if (!IsAlwaysExact<IntegerType, fromType>())                           \
    2725             :           return false;                                                        \
    2726             :         *result = IntegerType(*static_cast<fromType*>(data));                  \
    2727             :         return true;
    2728           0 :       CTYPES_FOR_EACH_INT_TYPE(INTEGER_CASE)
    2729           0 :       CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGER_CASE)
    2730             : #undef INTEGER_CASE
    2731             :       case TYPE_void_t:
    2732             :       case TYPE_bool:
    2733             :       case TYPE_float:
    2734             :       case TYPE_double:
    2735             :       case TYPE_float32_t:
    2736             :       case TYPE_float64_t:
    2737             :       case TYPE_char:
    2738             :       case TYPE_signed_char:
    2739             :       case TYPE_unsigned_char:
    2740             :       case TYPE_char16_t:
    2741             :       case TYPE_pointer:
    2742             :       case TYPE_function:
    2743             :       case TYPE_array:
    2744             :       case TYPE_struct:
    2745             :         // Not a compatible number type.
    2746           0 :         return false;
    2747             :       }
    2748             :     }
    2749             : 
    2750           0 :     if (Int64::IsInt64(obj)) {
    2751             :       // Make sure the integer fits in IntegerType.
    2752           0 :       int64_t i = Int64Base::GetInt(obj);
    2753           0 :       return ConvertExact(i, result);
    2754             :     }
    2755             : 
    2756           0 :     if (UInt64::IsUInt64(obj)) {
    2757             :       // Make sure the integer fits in IntegerType.
    2758           0 :       uint64_t i = Int64Base::GetInt(obj);
    2759           0 :       return ConvertExact(i, result);
    2760             :     }
    2761             : 
    2762           0 :     if (CDataFinalizer::IsCDataFinalizer(obj)) {
    2763           0 :       RootedValue innerData(cx);
    2764           0 :       if (!CDataFinalizer::GetValue(cx, obj, &innerData)) {
    2765           0 :         return false; // Nothing to convert
    2766             :       }
    2767           0 :       return jsvalToInteger(cx, innerData, result);
    2768             :     }
    2769             : 
    2770           0 :     return false;
    2771             :   }
    2772           0 :   if (val.isBoolean()) {
    2773             :     // Implicitly promote boolean values to 0 or 1, like C.
    2774           0 :     *result = val.toBoolean();
    2775           0 :     MOZ_ASSERT(*result == 0 || *result == 1);
    2776           0 :     return true;
    2777             :   }
    2778             :   // Don't silently convert null to an integer. It's probably a mistake.
    2779           0 :   return false;
    2780             : }
    2781             : 
    2782             : // Implicitly convert val to FloatType, allowing int, double,
    2783             : // Int64, UInt64, and CData numeric types 't' where all values of 't' are
    2784             : // representable by FloatType.
    2785             : template<class FloatType>
    2786             : static bool
    2787           0 : jsvalToFloat(JSContext* cx, HandleValue val, FloatType* result)
    2788             : {
    2789             :   JS_STATIC_ASSERT(!numeric_limits<FloatType>::is_exact);
    2790             : 
    2791             :   // The following casts may silently throw away some bits, but there's
    2792             :   // no good way around it. Sternly requiring that the 64-bit double
    2793             :   // argument be exactly representable as a 32-bit float is
    2794             :   // unrealistic: it would allow 1/2 to pass but not 1/3.
    2795           0 :   if (val.isInt32()) {
    2796           0 :     *result = FloatType(val.toInt32());
    2797           0 :     return true;
    2798             :   }
    2799           0 :   if (val.isDouble()) {
    2800           0 :     *result = FloatType(val.toDouble());
    2801           0 :     return true;
    2802             :   }
    2803           0 :   if (val.isObject()) {
    2804           0 :     JSObject* obj = &val.toObject();
    2805           0 :     if (CData::IsCData(obj)) {
    2806           0 :       JSObject* typeObj = CData::GetCType(obj);
    2807           0 :       void* data = CData::GetData(obj);
    2808             : 
    2809             :       // Check whether the source type is always representable, with exact
    2810             :       // precision, by the target type. If it is, convert the value.
    2811           0 :       switch (CType::GetTypeCode(typeObj)) {
    2812             : #define NUMERIC_CASE(name, fromType, ffiType)                                  \
    2813             :       case TYPE_##name:                                                        \
    2814             :         if (!IsAlwaysExact<FloatType, fromType>())                             \
    2815             :           return false;                                                        \
    2816             :         *result = FloatType(*static_cast<fromType*>(data));                    \
    2817             :         return true;
    2818           0 :       CTYPES_FOR_EACH_FLOAT_TYPE(NUMERIC_CASE)
    2819           0 :       CTYPES_FOR_EACH_INT_TYPE(NUMERIC_CASE)
    2820           0 :       CTYPES_FOR_EACH_WRAPPED_INT_TYPE(NUMERIC_CASE)
    2821             : #undef NUMERIC_CASE
    2822             :       case TYPE_void_t:
    2823             :       case TYPE_bool:
    2824             :       case TYPE_char:
    2825             :       case TYPE_signed_char:
    2826             :       case TYPE_unsigned_char:
    2827             :       case TYPE_char16_t:
    2828             :       case TYPE_pointer:
    2829             :       case TYPE_function:
    2830             :       case TYPE_array:
    2831             :       case TYPE_struct:
    2832             :         // Not a compatible number type.
    2833           0 :         return false;
    2834             :       }
    2835             :     }
    2836             :   }
    2837             :   // Don't silently convert true to 1.0 or false to 0.0, even though C/C++
    2838             :   // does it. It's likely to be a mistake.
    2839           0 :   return false;
    2840             : }
    2841             : 
    2842             : template <class IntegerType, class CharT>
    2843             : static bool
    2844           0 : StringToInteger(JSContext* cx, CharT* cp, size_t length, IntegerType* result,
    2845             :                 bool* overflow)
    2846             : {
    2847             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    2848             : 
    2849           0 :   const CharT* end = cp + length;
    2850           0 :   if (cp == end)
    2851           0 :     return false;
    2852             : 
    2853           0 :   IntegerType sign = 1;
    2854           0 :   if (cp[0] == '-') {
    2855             :     if (!numeric_limits<IntegerType>::is_signed)
    2856           0 :       return false;
    2857             : 
    2858           0 :     sign = -1;
    2859           0 :     ++cp;
    2860             :   }
    2861             : 
    2862             :   // Assume base-10, unless the string begins with '0x' or '0X'.
    2863           0 :   IntegerType base = 10;
    2864           0 :   if (end - cp > 2 && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) {
    2865           0 :     cp += 2;
    2866           0 :     base = 16;
    2867             :   }
    2868             : 
    2869             :   // Scan the string left to right and build the number,
    2870             :   // checking for valid characters 0 - 9, a - f, A - F and overflow.
    2871           0 :   IntegerType i = 0;
    2872           0 :   while (cp != end) {
    2873           0 :     char16_t c = *cp++;
    2874           0 :     if (c >= '0' && c <= '9')
    2875           0 :       c -= '0';
    2876           0 :     else if (base == 16 && c >= 'a' && c <= 'f')
    2877           0 :       c = c - 'a' + 10;
    2878           0 :     else if (base == 16 && c >= 'A' && c <= 'F')
    2879           0 :       c = c - 'A' + 10;
    2880             :     else
    2881           0 :       return false;
    2882             : 
    2883           0 :     IntegerType ii = i;
    2884           0 :     i = ii * base + sign * c;
    2885           0 :     if (i / base != ii) {
    2886           0 :       *overflow = true;
    2887           0 :       return false;
    2888             :     }
    2889             :   }
    2890             : 
    2891           0 :   *result = i;
    2892           0 :   return true;
    2893             : }
    2894             : 
    2895             : template<class IntegerType>
    2896             : static bool
    2897           0 : StringToInteger(JSContext* cx, JSString* string, IntegerType* result,
    2898             :                 bool* overflow)
    2899             : {
    2900           0 :   JSLinearString* linear = string->ensureLinear(cx);
    2901           0 :   if (!linear)
    2902           0 :     return false;
    2903             : 
    2904           0 :   AutoCheckCannotGC nogc;
    2905           0 :   size_t length = linear->length();
    2906           0 :   return string->hasLatin1Chars()
    2907           0 :          ? StringToInteger<IntegerType>(cx, linear->latin1Chars(nogc), length,
    2908             :                                         result, overflow)
    2909           0 :          : StringToInteger<IntegerType>(cx, linear->twoByteChars(nogc), length,
    2910           0 :                                         result, overflow);
    2911             : }
    2912             : 
    2913             : // Implicitly convert val to IntegerType, allowing int, double,
    2914             : // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
    2915             : // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
    2916             : template<class IntegerType>
    2917             : static bool
    2918           0 : jsvalToBigInteger(JSContext* cx,
    2919             :                   HandleValue val,
    2920             :                   bool allowString,
    2921             :                   IntegerType* result,
    2922             :                   bool* overflow)
    2923             : {
    2924             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    2925             : 
    2926           0 :   if (val.isInt32()) {
    2927             :     // Make sure the integer fits in the alotted precision, and has the right
    2928             :     // sign.
    2929           0 :     int32_t i = val.toInt32();
    2930           0 :     return ConvertExact(i, result);
    2931             :   }
    2932           0 :   if (val.isDouble()) {
    2933             :     // Don't silently lose bits here -- check that val really is an
    2934             :     // integer value, and has the right sign.
    2935           0 :     double d = val.toDouble();
    2936           0 :     return ConvertExact(d, result);
    2937             :   }
    2938           0 :   if (allowString && val.isString()) {
    2939             :     // Allow conversion from base-10 or base-16 strings, provided the result
    2940             :     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
    2941             :     // to the JS array element operator, which will automatically call
    2942             :     // toString() on the object for us.)
    2943           0 :     return StringToInteger(cx, val.toString(), result, overflow);
    2944             :   }
    2945           0 :   if (val.isObject()) {
    2946             :     // Allow conversion from an Int64 or UInt64 object directly.
    2947           0 :     JSObject* obj = &val.toObject();
    2948             : 
    2949           0 :     if (UInt64::IsUInt64(obj)) {
    2950             :       // Make sure the integer fits in IntegerType.
    2951           0 :       uint64_t i = Int64Base::GetInt(obj);
    2952           0 :       return ConvertExact(i, result);
    2953             :     }
    2954             : 
    2955           0 :     if (Int64::IsInt64(obj)) {
    2956             :       // Make sure the integer fits in IntegerType.
    2957           0 :       int64_t i = Int64Base::GetInt(obj);
    2958           0 :       return ConvertExact(i, result);
    2959             :     }
    2960             : 
    2961           0 :     if (CDataFinalizer::IsCDataFinalizer(obj)) {
    2962           0 :       RootedValue innerData(cx);
    2963           0 :       if (!CDataFinalizer::GetValue(cx, obj, &innerData)) {
    2964           0 :         return false; // Nothing to convert
    2965             :       }
    2966           0 :       return jsvalToBigInteger(cx, innerData, allowString, result, overflow);
    2967             :     }
    2968             : 
    2969             :   }
    2970           0 :   return false;
    2971             : }
    2972             : 
    2973             : // Implicitly convert val to a size value, where the size value is represented
    2974             : // by size_t but must also fit in a double.
    2975             : static bool
    2976           0 : jsvalToSize(JSContext* cx, HandleValue val, bool allowString, size_t* result)
    2977             : {
    2978             :   bool dummy;
    2979           0 :   if (!jsvalToBigInteger(cx, val, allowString, result, &dummy))
    2980           0 :     return false;
    2981             : 
    2982             :   // Also check that the result fits in a double.
    2983           0 :   return Convert<size_t>(double(*result)) == *result;
    2984             : }
    2985             : 
    2986             : // Implicitly convert val to IntegerType, allowing int, double,
    2987             : // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
    2988             : // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
    2989             : template<class IntegerType>
    2990             : static bool
    2991           0 : jsidToBigInteger(JSContext* cx,
    2992             :                  jsid val,
    2993             :                  bool allowString,
    2994             :                  IntegerType* result)
    2995             : {
    2996             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    2997             : 
    2998           0 :   if (JSID_IS_INT(val)) {
    2999             :     // Make sure the integer fits in the alotted precision, and has the right
    3000             :     // sign.
    3001           0 :     int32_t i = JSID_TO_INT(val);
    3002           0 :     return ConvertExact(i, result);
    3003             :   }
    3004           0 :   if (allowString && JSID_IS_STRING(val)) {
    3005             :     // Allow conversion from base-10 or base-16 strings, provided the result
    3006             :     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
    3007             :     // to the JS array element operator, which will automatically call
    3008             :     // toString() on the object for us.)
    3009             :     bool dummy;
    3010           0 :     return StringToInteger(cx, JSID_TO_STRING(val), result, &dummy);
    3011             :   }
    3012           0 :   return false;
    3013             : }
    3014             : 
    3015             : // Implicitly convert val to a size value, where the size value is represented
    3016             : // by size_t but must also fit in a double.
    3017             : static bool
    3018           0 : jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result)
    3019             : {
    3020           0 :   if (!jsidToBigInteger(cx, val, allowString, result))
    3021           0 :     return false;
    3022             : 
    3023             :   // Also check that the result fits in a double.
    3024           0 :   return Convert<size_t>(double(*result)) == *result;
    3025             : }
    3026             : 
    3027             : // Implicitly convert a size value to a Value, ensuring that the size_t value
    3028             : // fits in a double.
    3029             : static bool
    3030           0 : SizeTojsval(JSContext* cx, size_t size, MutableHandleValue result)
    3031             : {
    3032           0 :   if (Convert<size_t>(double(size)) != size) {
    3033           0 :     return false;
    3034             :   }
    3035             : 
    3036           0 :   result.setNumber(double(size));
    3037           0 :   return true;
    3038             : }
    3039             : 
    3040             : // Forcefully convert val to IntegerType when explicitly requested.
    3041             : template<class IntegerType>
    3042             : static bool
    3043           0 : jsvalToIntegerExplicit(HandleValue val, IntegerType* result)
    3044             : {
    3045             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    3046             : 
    3047           0 :   if (val.isDouble()) {
    3048             :     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
    3049           0 :     double d = val.toDouble();
    3050           0 :     *result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
    3051           0 :     return true;
    3052             :   }
    3053           0 :   if (val.isObject()) {
    3054             :     // Convert Int64 and UInt64 values by C-style cast.
    3055           0 :     JSObject* obj = &val.toObject();
    3056           0 :     if (Int64::IsInt64(obj)) {
    3057           0 :       int64_t i = Int64Base::GetInt(obj);
    3058           0 :       *result = IntegerType(i);
    3059           0 :       return true;
    3060             :     }
    3061           0 :     if (UInt64::IsUInt64(obj)) {
    3062           0 :       uint64_t i = Int64Base::GetInt(obj);
    3063           0 :       *result = IntegerType(i);
    3064           0 :       return true;
    3065             :     }
    3066             :   }
    3067           0 :   return false;
    3068             : }
    3069             : 
    3070             : // Forcefully convert val to a pointer value when explicitly requested.
    3071             : static bool
    3072           0 : jsvalToPtrExplicit(JSContext* cx, HandleValue val, uintptr_t* result)
    3073             : {
    3074           0 :   if (val.isInt32()) {
    3075             :     // int32_t always fits in intptr_t. If the integer is negative, cast through
    3076             :     // an intptr_t intermediate to sign-extend.
    3077           0 :     int32_t i = val.toInt32();
    3078           0 :     *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
    3079           0 :     return true;
    3080             :   }
    3081           0 :   if (val.isDouble()) {
    3082           0 :     double d = val.toDouble();
    3083           0 :     if (d < 0) {
    3084             :       // Cast through an intptr_t intermediate to sign-extend.
    3085           0 :       intptr_t i = Convert<intptr_t>(d);
    3086           0 :       if (double(i) != d)
    3087           0 :         return false;
    3088             : 
    3089           0 :       *result = uintptr_t(i);
    3090           0 :       return true;
    3091             :     }
    3092             : 
    3093             :     // Don't silently lose bits here -- check that val really is an
    3094             :     // integer value, and has the right sign.
    3095           0 :     *result = Convert<uintptr_t>(d);
    3096           0 :     return double(*result) == d;
    3097             :   }
    3098           0 :   if (val.isObject()) {
    3099           0 :     JSObject* obj = &val.toObject();
    3100           0 :     if (Int64::IsInt64(obj)) {
    3101           0 :       int64_t i = Int64Base::GetInt(obj);
    3102           0 :       intptr_t p = intptr_t(i);
    3103             : 
    3104             :       // Make sure the integer fits in the alotted precision.
    3105           0 :       if (int64_t(p) != i)
    3106           0 :         return false;
    3107           0 :       *result = uintptr_t(p);
    3108           0 :       return true;
    3109             :     }
    3110             : 
    3111           0 :     if (UInt64::IsUInt64(obj)) {
    3112           0 :       uint64_t i = Int64Base::GetInt(obj);
    3113             : 
    3114             :       // Make sure the integer fits in the alotted precision.
    3115           0 :       *result = uintptr_t(i);
    3116           0 :       return uint64_t(*result) == i;
    3117             :     }
    3118             :   }
    3119           0 :   return false;
    3120             : }
    3121             : 
    3122             : template<class IntegerType, class CharType, size_t N, class AP>
    3123             : void
    3124           0 : IntegerToString(IntegerType i, int radix, mozilla::Vector<CharType, N, AP>& result)
    3125             : {
    3126             :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    3127             : 
    3128             :   // The buffer must be big enough for all the bits of IntegerType to fit,
    3129             :   // in base-2, including '-'.
    3130             :   CharType buffer[sizeof(IntegerType) * 8 + 1];
    3131           0 :   CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
    3132           0 :   CharType* cp = end;
    3133             : 
    3134             :   // Build the string in reverse. We use multiplication and subtraction
    3135             :   // instead of modulus because that's much faster.
    3136           0 :   const bool isNegative = IsNegative(i);
    3137           0 :   size_t sign = isNegative ? -1 : 1;
    3138           0 :   do {
    3139           0 :     IntegerType ii = i / IntegerType(radix);
    3140           0 :     size_t index = sign * size_t(i - ii * IntegerType(radix));
    3141           0 :     *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[index];
    3142           0 :     i = ii;
    3143           0 :   } while (i != 0);
    3144             : 
    3145           0 :   if (isNegative)
    3146           0 :     *--cp = '-';
    3147             : 
    3148           0 :   MOZ_ASSERT(cp >= buffer);
    3149           0 :   if (!result.append(cp, end))
    3150           0 :     return;
    3151             : }
    3152             : 
    3153             : template<class CharType>
    3154             : static size_t
    3155           0 : strnlen(const CharType* begin, size_t max)
    3156             : {
    3157           0 :   for (const CharType* s = begin; s != begin + max; ++s)
    3158           0 :     if (*s == 0)
    3159           0 :       return s - begin;
    3160             : 
    3161           0 :   return max;
    3162             : }
    3163             : 
    3164             : // Convert C binary value 'data' of CType 'typeObj' to a JS primitive, where
    3165             : // possible; otherwise, construct and return a CData object. The following
    3166             : // semantics apply when constructing a CData object for return:
    3167             : // * If 'wantPrimitive' is true, the caller indicates that 'result' must be
    3168             : //   a JS primitive, and ConvertToJS will fail if 'result' would be a CData
    3169             : //   object. Otherwise:
    3170             : // * If a CData object 'parentObj' is supplied, the new CData object is
    3171             : //   dependent on the given parent and its buffer refers to a slice of the
    3172             : //   parent's buffer.
    3173             : // * If 'parentObj' is null, the new CData object may or may not own its
    3174             : //   resulting buffer depending on the 'ownResult' argument.
    3175             : static bool
    3176           0 : ConvertToJS(JSContext* cx,
    3177             :             HandleObject typeObj,
    3178             :             HandleObject parentObj,
    3179             :             void* data,
    3180             :             bool wantPrimitive,
    3181             :             bool ownResult,
    3182             :             MutableHandleValue result)
    3183             : {
    3184           0 :   MOZ_ASSERT(!parentObj || CData::IsCData(parentObj));
    3185           0 :   MOZ_ASSERT(!parentObj || !ownResult);
    3186           0 :   MOZ_ASSERT(!wantPrimitive || !ownResult);
    3187             : 
    3188           0 :   TypeCode typeCode = CType::GetTypeCode(typeObj);
    3189             : 
    3190           0 :   switch (typeCode) {
    3191             :   case TYPE_void_t:
    3192           0 :     result.setUndefined();
    3193           0 :     break;
    3194             :   case TYPE_bool:
    3195           0 :     result.setBoolean(*static_cast<bool*>(data));
    3196           0 :     break;
    3197             : #define INT_CASE(name, type, ffiType)                                          \
    3198             :   case TYPE_##name: {                                                          \
    3199             :     type value = *static_cast<type*>(data);                                    \
    3200             :     if (sizeof(type) < 4)                                                      \
    3201             :       result.setInt32(int32_t(value));                                         \
    3202             :     else                                                                       \
    3203             :       result.setDouble(double(value));                                         \
    3204             :     break;                                                                     \
    3205             :   }
    3206           0 :   CTYPES_FOR_EACH_INT_TYPE(INT_CASE)
    3207             : #undef INT_CASE
    3208             : #define WRAPPED_INT_CASE(name, type, ffiType)                                  \
    3209             :   case TYPE_##name: {                                                          \
    3210             :     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
    3211             :     uint64_t value;                                                            \
    3212             :     RootedObject proto(cx);                                                    \
    3213             :     if (!numeric_limits<type>::is_signed) {                                    \
    3214             :       value = *static_cast<type*>(data);                                       \
    3215             :       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
    3216             :       proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
    3217             :       if (!proto)                                                              \
    3218             :         return false;                                                          \
    3219             :     } else {                                                                   \
    3220             :       value = int64_t(*static_cast<type*>(data));                              \
    3221             :       /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */            \
    3222             :       proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO);           \
    3223             :       if (!proto)                                                              \
    3224             :         return false;                                                          \
    3225             :     }                                                                          \
    3226             :                                                                                \
    3227             :     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
    3228             :       !numeric_limits<type>::is_signed);                                       \
    3229             :     if (!obj)                                                                  \
    3230             :       return false;                                                            \
    3231             :     result.setObject(*obj);                                                    \
    3232             :     break;                                                                     \
    3233             :   }
    3234           0 :   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
    3235             : #undef WRAPPED_INT_CASE
    3236             : #define FLOAT_CASE(name, type, ffiType)                                        \
    3237             :   case TYPE_##name: {                                                          \
    3238             :     type value = *static_cast<type*>(data);                                    \
    3239             :     result.setDouble(double(value));                                           \
    3240             :     break;                                                                     \
    3241             :   }
    3242           0 :   CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
    3243             : #undef FLOAT_CASE
    3244             : #define CHAR_CASE(name, type, ffiType)                                         \
    3245             :   case TYPE_##name:                                                            \
    3246             :     /* Convert to an integer. We have no idea what character encoding to */    \
    3247             :     /* use, if any. */                                                         \
    3248             :     result.setInt32(*static_cast<type*>(data));                                \
    3249             :     break;
    3250           0 :   CTYPES_FOR_EACH_CHAR_TYPE(CHAR_CASE)
    3251             : #undef CHAR_CASE
    3252             :   case TYPE_char16_t: {
    3253             :     // Convert the char16_t to a 1-character string.
    3254           0 :     JSString* str = JS_NewUCStringCopyN(cx, static_cast<char16_t*>(data), 1);
    3255           0 :     if (!str)
    3256           0 :       return false;
    3257             : 
    3258           0 :     result.setString(str);
    3259           0 :     break;
    3260             :   }
    3261             :   case TYPE_pointer:
    3262             :   case TYPE_array:
    3263             :   case TYPE_struct: {
    3264             :     // We're about to create a new CData object to return. If the caller doesn't
    3265             :     // want this, return early.
    3266           0 :     if (wantPrimitive) {
    3267           0 :       return NonPrimitiveError(cx, typeObj);
    3268             :     }
    3269             : 
    3270           0 :     JSObject* obj = CData::Create(cx, typeObj, parentObj, data, ownResult);
    3271           0 :     if (!obj)
    3272           0 :       return false;
    3273             : 
    3274           0 :     result.setObject(*obj);
    3275           0 :     break;
    3276             :   }
    3277             :   case TYPE_function:
    3278           0 :     MOZ_CRASH("cannot return a FunctionType");
    3279             :   }
    3280             : 
    3281           0 :   return true;
    3282             : }
    3283             : 
    3284             : // Determine if the contents of a typed array can be converted without
    3285             : // ambiguity to a C type. Elements of a Int8Array are converted to
    3286             : // ctypes.int8_t, UInt8Array to ctypes.uint8_t, etc.
    3287           0 : bool CanConvertTypedArrayItemTo(JSObject* baseType, JSObject* valObj, JSContext* cx) {
    3288           0 :   TypeCode baseTypeCode = CType::GetTypeCode(baseType);
    3289           0 :   if (baseTypeCode == TYPE_void_t || baseTypeCode == TYPE_char) {
    3290           0 :     return true;
    3291             :   }
    3292             :   TypeCode elementTypeCode;
    3293           0 :   switch (JS_GetArrayBufferViewType(valObj)) {
    3294             :   case Scalar::Int8:
    3295           0 :     elementTypeCode = TYPE_int8_t;
    3296           0 :     break;
    3297             :   case Scalar::Uint8:
    3298             :   case Scalar::Uint8Clamped:
    3299           0 :     elementTypeCode = TYPE_uint8_t;
    3300           0 :     break;
    3301             :   case Scalar::Int16:
    3302           0 :     elementTypeCode = TYPE_int16_t;
    3303           0 :     break;
    3304             :   case Scalar::Uint16:
    3305           0 :     elementTypeCode = TYPE_uint16_t;
    3306           0 :     break;
    3307             :   case Scalar::Int32:
    3308           0 :     elementTypeCode = TYPE_int32_t;
    3309           0 :     break;
    3310             :   case Scalar::Uint32:
    3311           0 :     elementTypeCode = TYPE_uint32_t;
    3312           0 :     break;
    3313             :   case Scalar::Float32:
    3314           0 :     elementTypeCode = TYPE_float32_t;
    3315           0 :     break;
    3316             :   case Scalar::Float64:
    3317           0 :     elementTypeCode = TYPE_float64_t;
    3318           0 :     break;
    3319             :   default:
    3320           0 :     return false;
    3321             :   }
    3322             : 
    3323           0 :   return elementTypeCode == baseTypeCode;
    3324             : }
    3325             : 
    3326             : // Implicitly convert Value 'val' to a C binary representation of CType
    3327             : // 'targetType', storing the result in 'buffer'. Adequate space must be
    3328             : // provided in 'buffer' by the caller. This function generally does minimal
    3329             : // coercion between types. There are two cases in which this function is used:
    3330             : // 1) The target buffer is internal to a CData object; we simply write data
    3331             : //    into it.
    3332             : // 2) We are converting an argument for an ffi call, in which case 'convType'
    3333             : //    will be 'ConversionType::Argument'. This allows us to handle a special
    3334             : //    case: if necessary, we can autoconvert a JS string primitive to a
    3335             : //    pointer-to-character type. In this case, ownership of the allocated string
    3336             : //    is handed off to the caller; 'freePointer' will be set to indicate this.
    3337             : static bool
    3338           0 : ImplicitConvert(JSContext* cx,
    3339             :                 HandleValue val,
    3340             :                 JSObject* targetType_,
    3341             :                 void* buffer,
    3342             :                 ConversionType convType,
    3343             :                 bool* freePointer,
    3344             :                 HandleObject funObj = nullptr, unsigned argIndex = 0,
    3345             :                 HandleObject arrObj = nullptr, unsigned arrIndex = 0)
    3346             : {
    3347           0 :   RootedObject targetType(cx, targetType_);
    3348           0 :   MOZ_ASSERT(CType::IsSizeDefined(targetType));
    3349             : 
    3350             :   // First, check if val is either a CData object or a CDataFinalizer
    3351             :   // of type targetType.
    3352           0 :   JSObject* sourceData = nullptr;
    3353           0 :   JSObject* sourceType = nullptr;
    3354           0 :   RootedObject valObj(cx, nullptr);
    3355           0 :   if (val.isObject()) {
    3356           0 :     valObj = &val.toObject();
    3357           0 :     if (CData::IsCData(valObj)) {
    3358           0 :       sourceData = valObj;
    3359           0 :       sourceType = CData::GetCType(sourceData);
    3360             : 
    3361             :       // If the types are equal, copy the buffer contained within the CData.
    3362             :       // (Note that the buffers may overlap partially or completely.)
    3363           0 :       if (CType::TypesEqual(sourceType, targetType)) {
    3364           0 :         size_t size = CType::GetSize(sourceType);
    3365           0 :         memmove(buffer, CData::GetData(sourceData), size);
    3366           0 :         return true;
    3367             :       }
    3368           0 :     } else if (CDataFinalizer::IsCDataFinalizer(valObj)) {
    3369           0 :       sourceData = valObj;
    3370           0 :       sourceType = CDataFinalizer::GetCType(cx, sourceData);
    3371             : 
    3372             :       CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    3373           0 :         JS_GetPrivate(sourceData);
    3374             : 
    3375           0 :       if (!p) {
    3376             :         // We have called |dispose| or |forget| already.
    3377           0 :         return EmptyFinalizerError(cx, convType, funObj, argIndex);
    3378             :       }
    3379             : 
    3380             :       // If the types are equal, copy the buffer contained within the CData.
    3381           0 :       if (CType::TypesEqual(sourceType, targetType)) {
    3382           0 :         memmove(buffer, p->cargs, p->cargs_size);
    3383           0 :         return true;
    3384             :       }
    3385             :     }
    3386             :   }
    3387             : 
    3388           0 :   TypeCode targetCode = CType::GetTypeCode(targetType);
    3389             : 
    3390           0 :   switch (targetCode) {
    3391             :   case TYPE_bool: {
    3392             :     // Do not implicitly lose bits, but allow the values 0, 1, and -0.
    3393             :     // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
    3394             :     bool result;
    3395           0 :     if (!jsvalToBool(cx, val, &result))
    3396           0 :       return ConvError(cx, "boolean", val, convType, funObj, argIndex,
    3397           0 :                        arrObj, arrIndex);
    3398           0 :     *static_cast<bool*>(buffer) = result;
    3399           0 :     break;
    3400             :   }
    3401             : #define CHAR16_CASE(name, type, ffiType)                                       \
    3402             :   case TYPE_##name: {                                                          \
    3403             :     /* Convert from a 1-character string, regardless of encoding, */           \
    3404             :     /* or from an integer, provided the result fits in 'type'. */              \
    3405             :     type result;                                                               \
    3406             :     if (val.isString()) {                                                      \
    3407             :       JSString* str = val.toString();                                          \
    3408             :       if (str->length() != 1)                                                  \
    3409             :         return ConvError(cx, #name, val, convType, funObj, argIndex,           \
    3410             :                          arrObj, arrIndex);                                    \
    3411             :       JSLinearString* linear = str->ensureLinear(cx);                          \
    3412             :       if (!linear)                                                             \
    3413             :         return false;                                                          \
    3414             :       result = linear->latin1OrTwoByteChar(0);                                 \
    3415             :     } else if (!jsvalToInteger(cx, val, &result)) {                            \
    3416             :       return ConvError(cx, #name, val, convType, funObj, argIndex,             \
    3417             :                        arrObj, arrIndex);                                      \
    3418             :     }                                                                          \
    3419             :     *static_cast<type*>(buffer) = result;                                      \
    3420             :     break;                                                                     \
    3421             :   }
    3422           0 :   CTYPES_FOR_EACH_CHAR16_TYPE(CHAR16_CASE)
    3423             : #undef CHAR16_CASE
    3424             : #define INTEGRAL_CASE(name, type, ffiType)                                     \
    3425             :   case TYPE_##name: {                                                          \
    3426             :     /* Do not implicitly lose bits. */                                         \
    3427             :     type result;                                                               \
    3428             :     if (!jsvalToInteger(cx, val, &result))                                     \
    3429             :       return ConvError(cx, #name, val, convType, funObj, argIndex,             \
    3430             :                        arrObj, arrIndex);                                      \
    3431             :     *static_cast<type*>(buffer) = result;                                      \
    3432             :     break;                                                                     \
    3433             :   }
    3434           0 :   CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    3435           0 :   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
    3436             :   // It's hard to believe ctypes.char16_t("f") should work yet ctypes.char("f")
    3437             :   // should not.  Ditto for ctypes.{un,}signed_char.  But this is how ctypes
    3438             :   // has always worked, so preserve these semantics, and don't switch to an
    3439             :   // algorithm similar to that in DEFINE_CHAR16_TYPE above, just yet.
    3440           0 :   CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
    3441             : #undef INTEGRAL_CASE
    3442             : #define FLOAT_CASE(name, type, ffiType)                                        \
    3443             :   case TYPE_##name: {                                                          \
    3444             :     type result;                                                               \
    3445             :     if (!jsvalToFloat(cx, val, &result))                                       \
    3446             :       return ConvError(cx, #name, val, convType, funObj, argIndex,             \
    3447             :                        arrObj, arrIndex);                                      \
    3448             :     *static_cast<type*>(buffer) = result;                                      \
    3449             :     break;                                                                     \
    3450             :   }
    3451           0 :   CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
    3452             : #undef FLOAT_CASE
    3453             :   case TYPE_pointer: {
    3454           0 :     if (val.isNull()) {
    3455             :       // Convert to a null pointer.
    3456           0 :       *static_cast<void**>(buffer) = nullptr;
    3457           0 :       break;
    3458             :     }
    3459             : 
    3460           0 :     JS::Rooted<JSObject*> baseType(cx, PointerType::GetBaseType(targetType));
    3461           0 :     if (sourceData) {
    3462             :       // First, determine if the targetType is ctypes.void_t.ptr.
    3463           0 :       TypeCode sourceCode = CType::GetTypeCode(sourceType);
    3464           0 :       void* sourceBuffer = CData::GetData(sourceData);
    3465           0 :       bool voidptrTarget = CType::GetTypeCode(baseType) == TYPE_void_t;
    3466             : 
    3467           0 :       if (sourceCode == TYPE_pointer && voidptrTarget) {
    3468             :         // Autoconvert if targetType is ctypes.voidptr_t.
    3469           0 :         *static_cast<void**>(buffer) = *static_cast<void**>(sourceBuffer);
    3470           0 :         break;
    3471             :       }
    3472           0 :       if (sourceCode == TYPE_array) {
    3473             :         // Autoconvert an array to a ctypes.void_t.ptr or to
    3474             :         // sourceType.elementType.ptr, just like C.
    3475           0 :         JSObject* elementType = ArrayType::GetBaseType(sourceType);
    3476           0 :         if (voidptrTarget || CType::TypesEqual(baseType, elementType)) {
    3477           0 :           *static_cast<void**>(buffer) = sourceBuffer;
    3478           0 :           break;
    3479             :         }
    3480             :       }
    3481             : 
    3482           0 :     } else if (convType == ConversionType::Argument && val.isString()) {
    3483             :       // Convert the string for the ffi call. This requires allocating space
    3484             :       // which the caller assumes ownership of.
    3485             :       // TODO: Extend this so we can safely convert strings at other times also.
    3486           0 :       JSString* sourceString = val.toString();
    3487           0 :       size_t sourceLength = sourceString->length();
    3488           0 :       JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
    3489           0 :       if (!sourceLinear)
    3490           0 :         return false;
    3491             : 
    3492           0 :       switch (CType::GetTypeCode(baseType)) {
    3493             :       case TYPE_char:
    3494             :       case TYPE_signed_char:
    3495             :       case TYPE_unsigned_char: {
    3496             :         // Convert from UTF-16 to UTF-8.
    3497           0 :         size_t nbytes = GetDeflatedUTF8StringLength(cx, sourceLinear);
    3498           0 :         if (nbytes == (size_t) -1)
    3499           0 :           return false;
    3500             : 
    3501           0 :         char** charBuffer = static_cast<char**>(buffer);
    3502           0 :         *charBuffer = cx->pod_malloc<char>(nbytes + 1);
    3503           0 :         if (!*charBuffer) {
    3504           0 :           JS_ReportAllocationOverflow(cx);
    3505           0 :           return false;
    3506             :         }
    3507             : 
    3508           0 :         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceLinear, *charBuffer, &nbytes));
    3509           0 :         (*charBuffer)[nbytes] = 0;
    3510           0 :         *freePointer = true;
    3511           0 :         break;
    3512             :       }
    3513             :       case TYPE_char16_t: {
    3514             :         // Copy the char16_t string data. (We could provide direct access to the
    3515             :         // JSString's buffer, but this approach is safer if the caller happens
    3516             :         // to modify the string.)
    3517           0 :         char16_t** char16Buffer = static_cast<char16_t**>(buffer);
    3518           0 :         *char16Buffer = cx->pod_malloc<char16_t>(sourceLength + 1);
    3519           0 :         if (!*char16Buffer) {
    3520           0 :           JS_ReportAllocationOverflow(cx);
    3521           0 :           return false;
    3522             :         }
    3523             : 
    3524           0 :         *freePointer = true;
    3525           0 :         if (sourceLinear->hasLatin1Chars()) {
    3526           0 :             AutoCheckCannotGC nogc;
    3527           0 :             CopyAndInflateChars(*char16Buffer, sourceLinear->latin1Chars(nogc), sourceLength);
    3528             :         } else {
    3529           0 :             AutoCheckCannotGC nogc;
    3530           0 :             mozilla::PodCopy(*char16Buffer, sourceLinear->twoByteChars(nogc), sourceLength);
    3531             :         }
    3532           0 :         (*char16Buffer)[sourceLength] = 0;
    3533           0 :         break;
    3534             :       }
    3535             :       default:
    3536           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3537           0 :                          arrObj, arrIndex);
    3538             :       }
    3539           0 :       break;
    3540           0 :     } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
    3541             :       // Convert ArrayBuffer to pointer without any copy. This is only valid
    3542             :       // when converting an argument to a function call, as it is possible for
    3543             :       // the pointer to be invalidated by anything that runs JS code. (It is
    3544             :       // invalid to invoke JS code from a ctypes function call.)
    3545           0 :       if (convType != ConversionType::Argument) {
    3546           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3547           0 :                          arrObj, arrIndex);
    3548             :       }
    3549             :       void* ptr;
    3550             :       {
    3551           0 :           JS::AutoCheckCannotGC nogc;
    3552             :           bool isShared;
    3553           0 :           ptr = JS_GetArrayBufferData(valObj, &isShared, nogc);
    3554           0 :           MOZ_ASSERT(!isShared); // Because ArrayBuffer
    3555             :       }
    3556           0 :       if (!ptr) {
    3557           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3558           0 :                          arrObj, arrIndex);
    3559             :       }
    3560           0 :       *static_cast<void**>(buffer) = ptr;
    3561           0 :       break;
    3562           0 :     } else if (val.isObject() && JS_IsSharedArrayBufferObject(valObj)) {
    3563             :       // CTypes has not yet opted in to allowing shared memory pointers
    3564             :       // to escape.  Exporting a pointer to the shared buffer without
    3565             :       // indicating sharedness would expose client code to races.
    3566           0 :       return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3567           0 :                        arrObj, arrIndex);
    3568           0 :     } else if (val.isObject() && JS_IsArrayBufferViewObject(valObj)) {
    3569             :       // Same as ArrayBuffer, above, though note that this will take the
    3570             :       // offset of the view into account.
    3571           0 :       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
    3572           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3573           0 :                          arrObj, arrIndex);
    3574             :       }
    3575           0 :       if (convType != ConversionType::Argument) {
    3576           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3577           0 :                          arrObj, arrIndex);
    3578             :       }
    3579             :       void* ptr;
    3580             :       {
    3581           0 :           JS::AutoCheckCannotGC nogc;
    3582             :           bool isShared;
    3583           0 :           ptr = JS_GetArrayBufferViewData(valObj, &isShared, nogc);
    3584           0 :           if (isShared) {
    3585             :               // Opt out of shared memory, for now.  Exporting a
    3586             :               // pointer to the shared buffer without indicating
    3587             :               // sharedness would expose client code to races.
    3588           0 :               ptr = nullptr;
    3589             :           }
    3590             :       }
    3591           0 :       if (!ptr) {
    3592           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3593           0 :                          arrObj, arrIndex);
    3594             :       }
    3595           0 :       *static_cast<void**>(buffer) = ptr;
    3596           0 :       break;
    3597             :     }
    3598           0 :     return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3599           0 :                      arrObj, arrIndex);
    3600             :   }
    3601             :   case TYPE_array: {
    3602           0 :     MOZ_ASSERT(!funObj);
    3603             : 
    3604           0 :     RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
    3605           0 :     size_t targetLength = ArrayType::GetLength(targetType);
    3606             : 
    3607           0 :     if (val.isString()) {
    3608           0 :       JSString* sourceString = val.toString();
    3609           0 :       size_t sourceLength = sourceString->length();
    3610           0 :       JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
    3611           0 :       if (!sourceLinear)
    3612           0 :         return false;
    3613             : 
    3614           0 :       switch (CType::GetTypeCode(baseType)) {
    3615             :       case TYPE_char:
    3616             :       case TYPE_signed_char:
    3617             :       case TYPE_unsigned_char: {
    3618             :         // Convert from UTF-16 or Latin1 to UTF-8.
    3619             :         size_t nbytes =
    3620           0 :           GetDeflatedUTF8StringLength(cx, sourceLinear);
    3621           0 :         if (nbytes == (size_t) -1)
    3622           0 :           return false;
    3623             : 
    3624           0 :         if (targetLength < nbytes) {
    3625           0 :           MOZ_ASSERT(!funObj);
    3626           0 :           return ArrayLengthOverflow(cx, targetLength, targetType, nbytes, val,
    3627           0 :                                      convType);
    3628             :         }
    3629             : 
    3630           0 :         char* charBuffer = static_cast<char*>(buffer);
    3631           0 :         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceLinear, charBuffer,
    3632           0 :                                             &nbytes));
    3633             : 
    3634           0 :         if (targetLength > nbytes)
    3635           0 :           charBuffer[nbytes] = 0;
    3636             : 
    3637           0 :         break;
    3638             :       }
    3639             :       case TYPE_char16_t: {
    3640             :         // Copy the string data, char16_t for char16_t, including the terminator
    3641             :         // if there's space.
    3642           0 :         if (targetLength < sourceLength) {
    3643           0 :           MOZ_ASSERT(!funObj);
    3644           0 :           return ArrayLengthOverflow(cx, targetLength, targetType,
    3645           0 :                                      sourceLength, val, convType);
    3646             :         }
    3647             : 
    3648           0 :         char16_t* dest = static_cast<char16_t*>(buffer);
    3649           0 :         if (sourceLinear->hasLatin1Chars()) {
    3650           0 :             AutoCheckCannotGC nogc;
    3651           0 :             CopyAndInflateChars(dest, sourceLinear->latin1Chars(nogc), sourceLength);
    3652             :         } else {
    3653           0 :             AutoCheckCannotGC nogc;
    3654           0 :             mozilla::PodCopy(dest, sourceLinear->twoByteChars(nogc), sourceLength);
    3655             :         }
    3656             : 
    3657           0 :         if (targetLength > sourceLength)
    3658           0 :           dest[sourceLength] = 0;
    3659             : 
    3660           0 :         break;
    3661             :       }
    3662             :       default:
    3663           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3664           0 :                          arrObj, arrIndex);
    3665             :       }
    3666             :     } else {
    3667             :       ESClass cls;
    3668           0 :       if (!GetClassOfValue(cx, val, &cls))
    3669           0 :         return false;
    3670             : 
    3671           0 :       if (cls == ESClass::Array) {
    3672             :         // Convert each element of the array by calling ImplicitConvert.
    3673             :         uint32_t sourceLength;
    3674           0 :         if (!JS_GetArrayLength(cx, valObj, &sourceLength) ||
    3675           0 :             targetLength != size_t(sourceLength)) {
    3676           0 :           MOZ_ASSERT(!funObj);
    3677           0 :           return ArrayLengthMismatch(cx, targetLength, targetType,
    3678           0 :                                      size_t(sourceLength), val, convType);
    3679             :         }
    3680             : 
    3681             :         // Convert into an intermediate, in case of failure.
    3682           0 :         size_t elementSize = CType::GetSize(baseType);
    3683           0 :         size_t arraySize = elementSize * targetLength;
    3684           0 :         auto intermediate = cx->make_pod_array<char>(arraySize);
    3685           0 :         if (!intermediate) {
    3686           0 :           JS_ReportAllocationOverflow(cx);
    3687           0 :           return false;
    3688             :         }
    3689             : 
    3690           0 :         RootedValue item(cx);
    3691           0 :         for (uint32_t i = 0; i < sourceLength; ++i) {
    3692           0 :           if (!JS_GetElement(cx, valObj, i, &item))
    3693           0 :             return false;
    3694             : 
    3695           0 :           char* data = intermediate.get() + elementSize * i;
    3696           0 :           if (!ImplicitConvert(cx, item, baseType, data, convType, nullptr,
    3697           0 :                                funObj, argIndex, targetType, i))
    3698           0 :             return false;
    3699             :         }
    3700             : 
    3701           0 :         memcpy(buffer, intermediate.get(), arraySize);
    3702           0 :       } else if (cls == ESClass::ArrayBuffer || cls == ESClass::SharedArrayBuffer) {
    3703             :         // Check that array is consistent with type, then
    3704             :         // copy the array.
    3705           0 :         const bool bufferShared = cls == ESClass::SharedArrayBuffer;
    3706           0 :         uint32_t sourceLength = bufferShared ? JS_GetSharedArrayBufferByteLength(valObj)
    3707           0 :             : JS_GetArrayBufferByteLength(valObj);
    3708           0 :         size_t elementSize = CType::GetSize(baseType);
    3709           0 :         size_t arraySize = elementSize * targetLength;
    3710           0 :         if (arraySize != size_t(sourceLength)) {
    3711           0 :           MOZ_ASSERT(!funObj);
    3712           0 :           return ArrayLengthMismatch(cx, arraySize, targetType,
    3713           0 :                                      size_t(sourceLength), val, convType);
    3714             :         }
    3715           0 :         SharedMem<void*> target = SharedMem<void*>::unshared(buffer);
    3716           0 :         JS::AutoCheckCannotGC nogc;
    3717             :         bool isShared;
    3718             :         SharedMem<void*> src =
    3719             :             (bufferShared ?
    3720           0 :              SharedMem<void*>::shared(JS_GetSharedArrayBufferData(valObj, &isShared, nogc)) :
    3721           0 :              SharedMem<void*>::unshared(JS_GetArrayBufferData(valObj, &isShared, nogc)));
    3722           0 :         MOZ_ASSERT(isShared == bufferShared);
    3723           0 :         jit::AtomicOperations::memcpySafeWhenRacy(target, src, sourceLength);
    3724           0 :         break;
    3725           0 :       } else if (JS_IsTypedArrayObject(valObj)) {
    3726             :         // Check that array is consistent with type, then
    3727             :         // copy the array.  It is OK to copy from shared to unshared
    3728             :         // or vice versa.
    3729           0 :         if (!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
    3730           0 :           return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3731           0 :                            arrObj, arrIndex);
    3732             :         }
    3733             : 
    3734           0 :         uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
    3735           0 :         size_t elementSize = CType::GetSize(baseType);
    3736           0 :         size_t arraySize = elementSize * targetLength;
    3737           0 :         if (arraySize != size_t(sourceLength)) {
    3738           0 :           MOZ_ASSERT(!funObj);
    3739           0 :           return ArrayLengthMismatch(cx, arraySize, targetType,
    3740           0 :                                      size_t(sourceLength), val, convType);
    3741             :         }
    3742           0 :         SharedMem<void*> target = SharedMem<void*>::unshared(buffer);
    3743           0 :         JS::AutoCheckCannotGC nogc;
    3744             :         bool isShared;
    3745             :         SharedMem<void*> src =
    3746           0 :             SharedMem<void*>::shared(JS_GetArrayBufferViewData(valObj, &isShared, nogc));
    3747           0 :         jit::AtomicOperations::memcpySafeWhenRacy(target, src, sourceLength);
    3748           0 :         break;
    3749             :       } else {
    3750             :         // Don't implicitly convert to string. Users can implicitly convert
    3751             :         // with `String(x)` or `""+x`.
    3752           0 :         return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3753           0 :                          arrObj, arrIndex);
    3754             :       }
    3755             :     }
    3756           0 :     break;
    3757             :   }
    3758             :   case TYPE_struct: {
    3759           0 :     if (val.isObject() && !sourceData) {
    3760             :       // Enumerate the properties of the object; if they match the struct
    3761             :       // specification, convert the fields.
    3762           0 :       Rooted<IdVector> props(cx, IdVector(cx));
    3763           0 :       if (!JS_Enumerate(cx, valObj, &props))
    3764           0 :         return false;
    3765             : 
    3766             :       // Convert into an intermediate, in case of failure.
    3767           0 :       size_t structSize = CType::GetSize(targetType);
    3768           0 :       auto intermediate = cx->make_pod_array<char>(structSize);
    3769           0 :       if (!intermediate) {
    3770           0 :         JS_ReportAllocationOverflow(cx);
    3771           0 :         return false;
    3772             :       }
    3773             : 
    3774           0 :       const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
    3775           0 :       if (props.length() != fields->count()) {
    3776           0 :         return FieldCountMismatch(cx, fields->count(), targetType,
    3777           0 :                                   props.length(), val, convType,
    3778           0 :                                   funObj, argIndex);
    3779             :       }
    3780             : 
    3781           0 :       RootedId id(cx);
    3782           0 :       for (size_t i = 0; i < props.length(); ++i) {
    3783           0 :         id = props[i];
    3784             : 
    3785           0 :         if (!JSID_IS_STRING(id)) {
    3786           0 :           return PropNameNonStringError(cx, id, val, convType,
    3787           0 :                                         funObj, argIndex);
    3788             :         }
    3789             : 
    3790           0 :         JSFlatString* name = JSID_TO_FLAT_STRING(id);
    3791           0 :         const FieldInfo* field = StructType::LookupField(cx, targetType, name);
    3792           0 :         if (!field)
    3793           0 :           return false;
    3794             : 
    3795           0 :         RootedValue prop(cx);
    3796           0 :         if (!JS_GetPropertyById(cx, valObj, id, &prop))
    3797           0 :           return false;
    3798             : 
    3799             :         // Convert the field via ImplicitConvert().
    3800           0 :         char* fieldData = intermediate.get() + field->mOffset;
    3801           0 :         if (!ImplicitConvert(cx, prop, field->mType, fieldData, convType,
    3802           0 :                              nullptr, funObj, argIndex, targetType, i))
    3803           0 :           return false;
    3804             :       }
    3805             : 
    3806           0 :       memcpy(buffer, intermediate.get(), structSize);
    3807           0 :       break;
    3808             :     }
    3809             : 
    3810           0 :     return ConvError(cx, targetType, val, convType, funObj, argIndex,
    3811           0 :                      arrObj, arrIndex);
    3812             :   }
    3813             :   case TYPE_void_t:
    3814             :   case TYPE_function:
    3815           0 :     MOZ_CRASH("invalid type");
    3816             :   }
    3817             : 
    3818           0 :   return true;
    3819             : }
    3820             : 
    3821             : // Convert Value 'val' to a C binary representation of CType 'targetType',
    3822             : // storing the result in 'buffer'. This function is more forceful than
    3823             : // ImplicitConvert.
    3824             : static bool
    3825           0 : ExplicitConvert(JSContext* cx, HandleValue val, HandleObject targetType,
    3826             :                 void* buffer, ConversionType convType)
    3827             : {
    3828             :   // If ImplicitConvert succeeds, use that result.
    3829           0 :   if (ImplicitConvert(cx, val, targetType, buffer, convType, nullptr))
    3830           0 :     return true;
    3831             : 
    3832             :   // If ImplicitConvert failed, and there is no pending exception, then assume
    3833             :   // hard failure (out of memory, or some other similarly serious condition).
    3834             :   // We store any pending exception in case we need to re-throw it.
    3835           0 :   RootedValue ex(cx);
    3836           0 :   if (!JS_GetPendingException(cx, &ex))
    3837           0 :     return false;
    3838             : 
    3839             :   // Otherwise, assume soft failure. Clear the pending exception so that we
    3840             :   // can throw a different one as required.
    3841           0 :   JS_ClearPendingException(cx);
    3842             : 
    3843           0 :   TypeCode type = CType::GetTypeCode(targetType);
    3844             : 
    3845           0 :   switch (type) {
    3846             :   case TYPE_bool: {
    3847           0 :     *static_cast<bool*>(buffer) = ToBoolean(val);
    3848           0 :     break;
    3849             :   }
    3850             : #define INTEGRAL_CASE(name, type, ffiType)                                     \
    3851             :   case TYPE_##name: {                                                          \
    3852             :     /* Convert numeric values with a C-style cast, and */                      \
    3853             :     /* allow conversion from a base-10 or base-16 string. */                   \
    3854             :     type result;                                                               \
    3855             :     bool overflow = false;                                                     \
    3856             :     if (!jsvalToIntegerExplicit(val, &result) &&                               \
    3857             :         (!val.isString() ||                                                    \
    3858             :          !StringToInteger(cx, val.toString(), &result, &overflow))) {          \
    3859             :       if (overflow) {                                                          \
    3860             :         return TypeOverflow(cx, #name, val);                                   \
    3861             :       }                                                                        \
    3862             :       return ConvError(cx, #name, val, convType);                              \
    3863             :     }                                                                          \
    3864             :     *static_cast<type*>(buffer) = result;                                      \
    3865             :     break;                                                                     \
    3866             :   }
    3867           0 :   CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    3868           0 :   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
    3869           0 :   CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
    3870           0 :   CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
    3871             : #undef INTEGRAL_CASE
    3872             :   case TYPE_pointer: {
    3873             :     // Convert a number, Int64 object, or UInt64 object to a pointer.
    3874             :     uintptr_t result;
    3875           0 :     if (!jsvalToPtrExplicit(cx, val, &result))
    3876           0 :       return ConvError(cx, targetType, val, convType);
    3877           0 :     *static_cast<uintptr_t*>(buffer) = result;
    3878           0 :     break;
    3879             :   }
    3880             :   case TYPE_float32_t:
    3881             :   case TYPE_float64_t:
    3882             :   case TYPE_float:
    3883             :   case TYPE_double:
    3884             :   case TYPE_array:
    3885             :   case TYPE_struct:
    3886             :     // ImplicitConvert is sufficient. Re-throw the exception it generated.
    3887           0 :     JS_SetPendingException(cx, ex);
    3888           0 :     return false;
    3889             :   case TYPE_void_t:
    3890             :   case TYPE_function:
    3891           0 :     MOZ_CRASH("invalid type");
    3892             :   }
    3893           0 :   return true;
    3894             : }
    3895             : 
    3896             : // Given a CType 'typeObj', generate a string describing the C type declaration
    3897             : // corresponding to 'typeObj'. For instance, the CType constructed from
    3898             : // 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string
    3899             : // 'int32_t*(**)[4]'.
    3900             : static JSString*
    3901           0 : BuildTypeName(JSContext* cx, JSObject* typeObj_)
    3902             : {
    3903           0 :   AutoString result;
    3904           0 :   RootedObject typeObj(cx, typeObj_);
    3905             : 
    3906             :   // Walk the hierarchy of types, outermost to innermost, building up the type
    3907             :   // string. This consists of the base type, which goes on the left.
    3908             :   // Derived type modifiers (* and []) build from the inside outward, with
    3909             :   // pointers on the left and arrays on the right. An excellent description
    3910             :   // of the rules for building C type declarations can be found at:
    3911             :   // http://unixwiz.net/techtips/reading-cdecl.html
    3912           0 :   TypeCode prevGrouping = CType::GetTypeCode(typeObj), currentGrouping;
    3913             :   while (true) {
    3914           0 :     currentGrouping = CType::GetTypeCode(typeObj);
    3915           0 :     switch (currentGrouping) {
    3916             :     case TYPE_pointer: {
    3917             :       // Pointer types go on the left.
    3918           0 :       PrependString(result, "*");
    3919             : 
    3920           0 :       typeObj = PointerType::GetBaseType(typeObj);
    3921           0 :       prevGrouping = currentGrouping;
    3922           0 :       continue;
    3923             :     }
    3924             :     case TYPE_array: {
    3925           0 :       if (prevGrouping == TYPE_pointer) {
    3926             :         // Outer type is pointer, inner type is array. Grouping is required.
    3927           0 :         PrependString(result, "(");
    3928           0 :         AppendString(result, ")");
    3929             :       }
    3930             : 
    3931             :       // Array types go on the right.
    3932           0 :       AppendString(result, "[");
    3933             :       size_t length;
    3934           0 :       if (ArrayType::GetSafeLength(typeObj, &length))
    3935           0 :         IntegerToString(length, 10, result);
    3936             : 
    3937           0 :       AppendString(result, "]");
    3938             : 
    3939           0 :       typeObj = ArrayType::GetBaseType(typeObj);
    3940           0 :       prevGrouping = currentGrouping;
    3941           0 :       continue;
    3942             :     }
    3943             :     case TYPE_function: {
    3944           0 :       FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    3945             : 
    3946             :       // Add in the calling convention, if it's not cdecl.
    3947             :       // There's no trailing or leading space needed here, as none of the
    3948             :       // modifiers can produce a string beginning with an identifier ---
    3949             :       // except for TYPE_function itself, which is fine because functions
    3950             :       // can't return functions.
    3951           0 :       ABICode abi = GetABICode(fninfo->mABI);
    3952           0 :       if (abi == ABI_STDCALL)
    3953           0 :         PrependString(result, "__stdcall");
    3954           0 :       else if (abi == ABI_THISCALL)
    3955           0 :         PrependString(result, "__thiscall");
    3956           0 :       else if (abi == ABI_WINAPI)
    3957           0 :         PrependString(result, "WINAPI");
    3958             : 
    3959             :       // Function application binds more tightly than dereferencing, so
    3960             :       // wrap pointer types in parens. Functions can't return functions
    3961             :       // (only pointers to them), and arrays can't hold functions
    3962             :       // (similarly), so we don't need to address those cases.
    3963           0 :       if (prevGrouping == TYPE_pointer) {
    3964           0 :         PrependString(result, "(");
    3965           0 :         AppendString(result, ")");
    3966             :       }
    3967             : 
    3968             :       // Argument list goes on the right.
    3969           0 :       AppendString(result, "(");
    3970           0 :       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    3971           0 :         RootedObject argType(cx, fninfo->mArgTypes[i]);
    3972           0 :         JSString* argName = CType::GetName(cx, argType);
    3973           0 :         AppendString(result, argName);
    3974           0 :         if (i != fninfo->mArgTypes.length() - 1 ||
    3975           0 :             fninfo->mIsVariadic)
    3976           0 :           AppendString(result, ", ");
    3977             :       }
    3978           0 :       if (fninfo->mIsVariadic)
    3979           0 :         AppendString(result, "...");
    3980           0 :       AppendString(result, ")");
    3981             : 
    3982             :       // Set 'typeObj' to the return type, and let the loop process it.
    3983             :       // 'prevGrouping' doesn't matter here, because functions cannot return
    3984             :       // arrays -- thus the parenthetical rules don't get tickled.
    3985           0 :       typeObj = fninfo->mReturnType;
    3986           0 :       continue;
    3987             :     }
    3988             :     default:
    3989             :       // Either a basic or struct type. Use the type's name as the base type.
    3990           0 :       break;
    3991             :     }
    3992           0 :     break;
    3993           0 :   }
    3994             : 
    3995             :   // If prepending the base type name directly would splice two
    3996             :   // identifiers, insert a space.
    3997           0 :   if (('a' <= result[0] && result[0] <= 'z') ||
    3998           0 :       ('A' <= result[0] && result[0] <= 'Z') ||
    3999           0 :       (result[0] == '_'))
    4000           0 :     PrependString(result, " ");
    4001             : 
    4002             :   // Stick the base type and derived type parts together.
    4003           0 :   JSString* baseName = CType::GetName(cx, typeObj);
    4004           0 :   PrependString(result, baseName);
    4005           0 :   return NewUCString(cx, result);
    4006             : }
    4007             : 
    4008             : // Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
    4009             : // would construct the same CType. If 'makeShort' is true, assume that any
    4010             : // StructType 't' is bound to an in-scope variable of name 't.name', and use
    4011             : // that variable in place of generating a string to construct the type 't'.
    4012             : // (This means the type comparison function CType::TypesEqual will return true
    4013             : // when comparing the input and output of BuildTypeSource, since struct
    4014             : // equality is determined by strict JSObject pointer equality.)
    4015             : static void
    4016           0 : BuildTypeSource(JSContext* cx,
    4017             :                 JSObject* typeObj_,
    4018             :                 bool makeShort,
    4019             :                 AutoString& result)
    4020             : {
    4021           0 :   RootedObject typeObj(cx, typeObj_);
    4022             : 
    4023             :   // Walk the types, building up the toSource() string.
    4024           0 :   switch (CType::GetTypeCode(typeObj)) {
    4025             :   case TYPE_void_t:
    4026             : #define CASE_FOR_TYPE(name, type, ffiType)  case TYPE_##name:
    4027             :   CTYPES_FOR_EACH_TYPE(CASE_FOR_TYPE)
    4028             : #undef CASE_FOR_TYPE
    4029             :   {
    4030           0 :     AppendString(result, "ctypes.");
    4031           0 :     JSString* nameStr = CType::GetName(cx, typeObj);
    4032           0 :     AppendString(result, nameStr);
    4033           0 :     break;
    4034             :   }
    4035             :   case TYPE_pointer: {
    4036           0 :     RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
    4037             : 
    4038             :     // Specialcase ctypes.voidptr_t.
    4039           0 :     if (CType::GetTypeCode(baseType) == TYPE_void_t) {
    4040           0 :       AppendString(result, "ctypes.voidptr_t");
    4041           0 :       break;
    4042             :     }
    4043             : 
    4044             :     // Recursively build the source string, and append '.ptr'.
    4045           0 :     BuildTypeSource(cx, baseType, makeShort, result);
    4046           0 :     AppendString(result, ".ptr");
    4047           0 :     break;
    4048             :   }
    4049             :   case TYPE_function: {
    4050           0 :     FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    4051             : 
    4052           0 :     AppendString(result, "ctypes.FunctionType(");
    4053             : 
    4054           0 :     switch (GetABICode(fninfo->mABI)) {
    4055             :     case ABI_DEFAULT:
    4056           0 :       AppendString(result, "ctypes.default_abi, ");
    4057           0 :       break;
    4058             :     case ABI_STDCALL:
    4059           0 :       AppendString(result, "ctypes.stdcall_abi, ");
    4060           0 :       break;
    4061             :     case ABI_THISCALL:
    4062           0 :       AppendString(result, "ctypes.thiscall_abi, ");
    4063           0 :       break;
    4064             :     case ABI_WINAPI:
    4065           0 :       AppendString(result, "ctypes.winapi_abi, ");
    4066           0 :       break;
    4067             :     case INVALID_ABI:
    4068           0 :       MOZ_CRASH("invalid abi");
    4069             :     }
    4070             : 
    4071             :     // Recursively build the source string describing the function return and
    4072             :     // argument types.
    4073           0 :     BuildTypeSource(cx, fninfo->mReturnType, true, result);
    4074             : 
    4075           0 :     if (fninfo->mArgTypes.length() > 0) {
    4076           0 :       AppendString(result, ", [");
    4077           0 :       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    4078           0 :         BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
    4079           0 :         if (i != fninfo->mArgTypes.length() - 1 ||
    4080           0 :             fninfo->mIsVariadic)
    4081           0 :           AppendString(result, ", ");
    4082             :       }
    4083           0 :       if (fninfo->mIsVariadic)
    4084           0 :         AppendString(result, "\"...\"");
    4085           0 :       AppendString(result, "]");
    4086             :     }
    4087             : 
    4088           0 :     AppendString(result, ")");
    4089           0 :     break;
    4090             :   }
    4091             :   case TYPE_array: {
    4092             :     // Recursively build the source string, and append '.array(n)',
    4093             :     // where n is the array length, or the empty string if the array length
    4094             :     // is undefined.
    4095           0 :     JSObject* baseType = ArrayType::GetBaseType(typeObj);
    4096           0 :     BuildTypeSource(cx, baseType, makeShort, result);
    4097           0 :     AppendString(result, ".array(");
    4098             : 
    4099             :     size_t length;
    4100           0 :     if (ArrayType::GetSafeLength(typeObj, &length))
    4101           0 :       IntegerToString(length, 10, result);
    4102             : 
    4103           0 :     AppendString(result, ")");
    4104           0 :     break;
    4105             :   }
    4106             :   case TYPE_struct: {
    4107           0 :     JSString* name = CType::GetName(cx, typeObj);
    4108             : 
    4109           0 :     if (makeShort) {
    4110             :       // Shorten the type declaration by assuming that StructType 't' is bound
    4111             :       // to an in-scope variable of name 't.name'.
    4112           0 :       AppendString(result, name);
    4113           0 :       break;
    4114             :     }
    4115             : 
    4116             :     // Write the full struct declaration.
    4117           0 :     AppendString(result, "ctypes.StructType(\"");
    4118           0 :     AppendString(result, name);
    4119           0 :     AppendString(result, "\"");
    4120             : 
    4121             :     // If it's an opaque struct, we're done.
    4122           0 :     if (!CType::IsSizeDefined(typeObj)) {
    4123           0 :       AppendString(result, ")");
    4124           0 :       break;
    4125             :     }
    4126             : 
    4127           0 :     AppendString(result, ", [");
    4128             : 
    4129           0 :     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
    4130           0 :     size_t length = fields->count();
    4131           0 :     Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
    4132           0 :     if (!fieldsArray.resize(length))
    4133           0 :       break;
    4134             : 
    4135           0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
    4136           0 :       fieldsArray[r.front().value().mIndex] = &r.front();
    4137             : 
    4138           0 :     for (size_t i = 0; i < length; ++i) {
    4139           0 :       const FieldInfoHash::Entry* entry = fieldsArray[i];
    4140           0 :       AppendString(result, "{ \"");
    4141           0 :       AppendString(result, entry->key());
    4142           0 :       AppendString(result, "\": ");
    4143           0 :       BuildTypeSource(cx, entry->value().mType, true, result);
    4144           0 :       AppendString(result, " }");
    4145           0 :       if (i != length - 1)
    4146           0 :         AppendString(result, ", ");
    4147             :     }
    4148             : 
    4149           0 :     AppendString(result, "])");
    4150           0 :     break;
    4151             :   }
    4152             :   }
    4153           0 : }
    4154             : 
    4155             : // Given a CData object of CType 'typeObj' with binary value 'data', generate a
    4156             : // string 'result' such that 'eval(result)' would construct a CData object with
    4157             : // the same CType and containing the same binary value. This assumes that any
    4158             : // StructType 't' is bound to an in-scope variable of name 't.name'. (This means
    4159             : // the type comparison function CType::TypesEqual will return true when
    4160             : // comparing the types, since struct equality is determined by strict JSObject
    4161             : // pointer equality.) Further, if 'isImplicit' is true, ensure that the
    4162             : // resulting string can ImplicitConvert successfully if passed to another data
    4163             : // constructor. (This is important when called recursively, since fields of
    4164             : // structs and arrays are converted with ImplicitConvert.)
    4165             : static bool
    4166           0 : BuildDataSource(JSContext* cx,
    4167             :                 HandleObject typeObj,
    4168             :                 void* data,
    4169             :                 bool isImplicit,
    4170             :                 AutoString& result)
    4171             : {
    4172           0 :   TypeCode type = CType::GetTypeCode(typeObj);
    4173           0 :   switch (type) {
    4174             :   case TYPE_bool:
    4175           0 :     if (*static_cast<bool*>(data))
    4176           0 :       AppendString(result, "true");
    4177             :     else
    4178           0 :       AppendString(result, "false");
    4179           0 :     break;
    4180             : #define INTEGRAL_CASE(name, type, ffiType)                                     \
    4181             :   case TYPE_##name:                                                            \
    4182             :     /* Serialize as a primitive decimal integer. */                            \
    4183             :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    4184             :     break;
    4185           0 :   CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    4186             : #undef INTEGRAL_CASE
    4187             : #define WRAPPED_INT_CASE(name, type, ffiType)                                  \
    4188             :   case TYPE_##name:                                                            \
    4189             :     /* Serialize as a wrapped decimal integer. */                              \
    4190             :     if (!numeric_limits<type>::is_signed)                                      \
    4191             :       AppendString(result, "ctypes.UInt64(\"");                                \
    4192             :     else                                                                       \
    4193             :       AppendString(result, "ctypes.Int64(\"");                                 \
    4194             :                                                                                \
    4195             :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    4196             :     AppendString(result, "\")");                                               \
    4197             :     break;
    4198           0 :   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
    4199             : #undef WRAPPED_INT_CASE
    4200             : #define FLOAT_CASE(name, type, ffiType)                                        \
    4201             :   case TYPE_##name: {                                                          \
    4202             :     /* Serialize as a primitive double. */                                     \
    4203             :     double fp = *static_cast<type*>(data);                                     \
    4204             :     ToCStringBuf cbuf;                                                         \
    4205             :     char* str = NumberToCString(cx, &cbuf, fp);                                \
    4206             :     if (!str || !result.append(str, strlen(str))) {                            \
    4207             :       JS_ReportOutOfMemory(cx);                                                \
    4208             :       return false;                                                            \
    4209             :     }                                                                          \
    4210             :     break;                                                                     \
    4211             :   }
    4212           0 :   CTYPES_FOR_EACH_FLOAT_TYPE(FLOAT_CASE)
    4213             : #undef FLOAT_CASE
    4214             : #define CHAR_CASE(name, type, ffiType)                                         \
    4215             :   case TYPE_##name:                                                            \
    4216             :     /* Serialize as an integer. */                                             \
    4217             :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    4218             :     break;
    4219           0 :   CTYPES_FOR_EACH_CHAR_TYPE(CHAR_CASE)
    4220             : #undef CHAR_CASE
    4221             :   case TYPE_char16_t: {
    4222             :     // Serialize as a 1-character JS string.
    4223           0 :     JSString* str = JS_NewUCStringCopyN(cx, static_cast<char16_t*>(data), 1);
    4224           0 :     if (!str)
    4225           0 :       return false;
    4226             : 
    4227             :     // Escape characters, and quote as necessary.
    4228           0 :     RootedValue valStr(cx, StringValue(str));
    4229           0 :     JSString* src = JS_ValueToSource(cx, valStr);
    4230           0 :     if (!src)
    4231           0 :       return false;
    4232             : 
    4233           0 :     AppendString(result, src);
    4234           0 :     break;
    4235             :   }
    4236             :   case TYPE_pointer:
    4237             :   case TYPE_function: {
    4238           0 :     if (isImplicit) {
    4239             :       // The result must be able to ImplicitConvert successfully.
    4240             :       // Wrap in a type constructor, then serialize for ExplicitConvert.
    4241           0 :       BuildTypeSource(cx, typeObj, true, result);
    4242           0 :       AppendString(result, "(");
    4243             :     }
    4244             : 
    4245             :     // Serialize the pointer value as a wrapped hexadecimal integer.
    4246           0 :     uintptr_t ptr = *static_cast<uintptr_t*>(data);
    4247           0 :     AppendString(result, "ctypes.UInt64(\"0x");
    4248           0 :     IntegerToString(ptr, 16, result);
    4249           0 :     AppendString(result, "\")");
    4250             : 
    4251           0 :     if (isImplicit)
    4252           0 :       AppendString(result, ")");
    4253             : 
    4254           0 :     break;
    4255             :   }
    4256             :   case TYPE_array: {
    4257             :     // Serialize each element of the array recursively. Each element must
    4258             :     // be able to ImplicitConvert successfully.
    4259           0 :     RootedObject baseType(cx, ArrayType::GetBaseType(typeObj));
    4260           0 :     AppendString(result, "[");
    4261             : 
    4262           0 :     size_t length = ArrayType::GetLength(typeObj);
    4263           0 :     size_t elementSize = CType::GetSize(baseType);
    4264           0 :     for (size_t i = 0; i < length; ++i) {
    4265           0 :       char* element = static_cast<char*>(data) + elementSize * i;
    4266           0 :       if (!BuildDataSource(cx, baseType, element, true, result))
    4267           0 :         return false;
    4268             : 
    4269           0 :       if (i + 1 < length)
    4270           0 :         AppendString(result, ", ");
    4271             :     }
    4272           0 :     AppendString(result, "]");
    4273           0 :     break;
    4274             :   }
    4275             :   case TYPE_struct: {
    4276           0 :     if (isImplicit) {
    4277             :       // The result must be able to ImplicitConvert successfully.
    4278             :       // Serialize the data as an object with properties, rather than
    4279             :       // a sequence of arguments to the StructType constructor.
    4280           0 :       AppendString(result, "{");
    4281             :     }
    4282             : 
    4283             :     // Serialize each field of the struct recursively. Each field must
    4284             :     // be able to ImplicitConvert successfully.
    4285           0 :     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
    4286           0 :     size_t length = fields->count();
    4287           0 :     Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
    4288           0 :     if (!fieldsArray.resize(length))
    4289           0 :       return false;
    4290             : 
    4291           0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
    4292           0 :       fieldsArray[r.front().value().mIndex] = &r.front();
    4293             : 
    4294           0 :     for (size_t i = 0; i < length; ++i) {
    4295           0 :       const FieldInfoHash::Entry* entry = fieldsArray[i];
    4296             : 
    4297           0 :       if (isImplicit) {
    4298           0 :         AppendString(result, "\"");
    4299           0 :         AppendString(result, entry->key());
    4300           0 :         AppendString(result, "\": ");
    4301             :       }
    4302             : 
    4303           0 :       char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
    4304           0 :       RootedObject entryType(cx, entry->value().mType);
    4305           0 :       if (!BuildDataSource(cx, entryType, fieldData, true, result))
    4306           0 :         return false;
    4307             : 
    4308           0 :       if (i + 1 != length)
    4309           0 :         AppendString(result, ", ");
    4310             :     }
    4311             : 
    4312           0 :     if (isImplicit)
    4313           0 :       AppendString(result, "}");
    4314             : 
    4315           0 :     break;
    4316             :   }
    4317             :   case TYPE_void_t:
    4318           0 :     MOZ_CRASH("invalid type");
    4319             :   }
    4320             : 
    4321           0 :   return true;
    4322             : }
    4323             : 
    4324             : /*******************************************************************************
    4325             : ** JSAPI callback function implementations
    4326             : *******************************************************************************/
    4327             : 
    4328             : bool
    4329           0 : ConstructAbstract(JSContext* cx,
    4330             :                   unsigned argc,
    4331             :                   Value* vp)
    4332             : {
    4333             :   // Calling an abstract base class constructor is disallowed.
    4334           0 :   return CannotConstructError(cx, "abstract type");
    4335             : }
    4336             : 
    4337             : /*******************************************************************************
    4338             : ** CType implementation
    4339             : *******************************************************************************/
    4340             : 
    4341             : bool
    4342           0 : CType::ConstructData(JSContext* cx,
    4343             :                      unsigned argc,
    4344             :                      Value* vp)
    4345             : {
    4346           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    4347             :   // get the callee object...
    4348           0 :   RootedObject obj(cx, &args.callee());
    4349           0 :   if (!CType::IsCType(obj)) {
    4350           0 :     return IncompatibleCallee(cx, "CType constructor", obj);
    4351             :   }
    4352             : 
    4353             :   // How we construct the CData object depends on what type we represent.
    4354             :   // An instance 'd' of a CData object of type 't' has:
    4355             :   //   * [[Class]] "CData"
    4356             :   //   * __proto__ === t.prototype
    4357           0 :   switch (GetTypeCode(obj)) {
    4358             :   case TYPE_void_t:
    4359           0 :     return CannotConstructError(cx, "void_t");
    4360             :   case TYPE_function:
    4361             :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    4362           0 :                               CTYPESMSG_FUNCTION_CONSTRUCT);
    4363           0 :     return false;
    4364             :   case TYPE_pointer:
    4365           0 :     return PointerType::ConstructData(cx, obj, args);
    4366             :   case TYPE_array:
    4367           0 :     return ArrayType::ConstructData(cx, obj, args);
    4368             :   case TYPE_struct:
    4369           0 :     return StructType::ConstructData(cx, obj, args);
    4370             :   default:
    4371           0 :     return ConstructBasic(cx, obj, args);
    4372             :   }
    4373             : }
    4374             : 
    4375             : bool
    4376           0 : CType::ConstructBasic(JSContext* cx,
    4377             :                       HandleObject obj,
    4378             :                       const CallArgs& args)
    4379             : {
    4380           0 :   if (args.length() > 1) {
    4381           0 :     return ArgumentLengthError(cx, "CType constructor", "at most one", "");
    4382             :   }
    4383             : 
    4384             :   // construct a CData object
    4385           0 :   RootedObject result(cx, CData::Create(cx, obj, nullptr, nullptr, true));
    4386           0 :   if (!result)
    4387           0 :     return false;
    4388             : 
    4389           0 :   if (args.length() == 1) {
    4390           0 :     if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result),
    4391             :                          ConversionType::Construct))
    4392           0 :       return false;
    4393             :   }
    4394             : 
    4395           0 :   args.rval().setObject(*result);
    4396           0 :   return true;
    4397             : }
    4398             : 
    4399             : JSObject*
    4400          72 : CType::Create(JSContext* cx,
    4401             :               HandleObject typeProto,
    4402             :               HandleObject dataProto,
    4403             :               TypeCode type,
    4404             :               JSString* name_,
    4405             :               HandleValue size,
    4406             :               HandleValue align,
    4407             :               ffi_type* ffiType)
    4408             : {
    4409         144 :   RootedString name(cx, name_);
    4410             : 
    4411             :   // Create a CType object with the properties and slots common to all CTypes.
    4412             :   // Each type object 't' has:
    4413             :   //   * [[Class]] "CType"
    4414             :   //   * __proto__ === 'typeProto'; one of ctypes.{CType,PointerType,ArrayType,
    4415             :   //     StructType}.prototype
    4416             :   //   * A constructor which creates and returns a CData object, containing
    4417             :   //     binary data of the given type.
    4418             :   //   * 'prototype' property:
    4419             :   //     * [[Class]] "CDataProto"
    4420             :   //     * __proto__ === 'dataProto'; an object containing properties and
    4421             :   //       functions common to all CData objects of types derived from
    4422             :   //       'typeProto'. (For instance, this could be ctypes.CData.prototype
    4423             :   //       for simple types, or something representing structs for StructTypes.)
    4424             :   //     * 'constructor' property === 't'
    4425             :   //     * Additional properties specified by 'ps', as appropriate for the
    4426             :   //       specific type instance 't'.
    4427         144 :   RootedObject typeObj(cx, JS_NewObjectWithGivenProto(cx, &sCTypeClass, typeProto));
    4428          72 :   if (!typeObj)
    4429           0 :     return nullptr;
    4430             : 
    4431             :   // Set up the reserved slots.
    4432          72 :   JS_SetReservedSlot(typeObj, SLOT_TYPECODE, Int32Value(type));
    4433          72 :   if (ffiType)
    4434          68 :     JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PrivateValue(ffiType));
    4435          72 :   if (name)
    4436          66 :     JS_SetReservedSlot(typeObj, SLOT_NAME, StringValue(name));
    4437          72 :   JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
    4438          72 :   JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
    4439             : 
    4440          72 :   if (dataProto) {
    4441             :     // Set up the 'prototype' and 'prototype.constructor' properties.
    4442         136 :     RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto));
    4443          68 :     if (!prototype)
    4444           0 :       return nullptr;
    4445             : 
    4446          68 :     if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
    4447             :                            JSPROP_READONLY | JSPROP_PERMANENT))
    4448           0 :       return nullptr;
    4449             : 
    4450             :     // Set the 'prototype' object.
    4451             :     //if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
    4452             :     //  return nullptr;
    4453          68 :     JS_SetReservedSlot(typeObj, SLOT_PROTO, ObjectValue(*prototype));
    4454             :   }
    4455             : 
    4456          72 :   if (!JS_FreezeObject(cx, typeObj))
    4457           0 :     return nullptr;
    4458             : 
    4459             :   // Assert a sanity check on size and alignment: size % alignment should always
    4460             :   // be zero.
    4461          72 :   MOZ_ASSERT_IF(IsSizeDefined(typeObj),
    4462             :                 GetSize(typeObj) % GetAlignment(typeObj) == 0);
    4463             : 
    4464          72 :   return typeObj;
    4465             : }
    4466             : 
    4467             : JSObject*
    4468          62 : CType::DefineBuiltin(JSContext* cx,
    4469             :                      HandleObject ctypesObj,
    4470             :                      const char* propName,
    4471             :                      JSObject* typeProto_,
    4472             :                      JSObject* dataProto_,
    4473             :                      const char* name,
    4474             :                      TypeCode type,
    4475             :                      HandleValue size,
    4476             :                      HandleValue align,
    4477             :                      ffi_type* ffiType)
    4478             : {
    4479         124 :   RootedObject typeProto(cx, typeProto_);
    4480         124 :   RootedObject dataProto(cx, dataProto_);
    4481             : 
    4482         124 :   RootedString nameStr(cx, JS_NewStringCopyZ(cx, name));
    4483          62 :   if (!nameStr)
    4484           0 :     return nullptr;
    4485             : 
    4486             :   // Create a new CType object with the common properties and slots.
    4487         124 :   RootedObject typeObj(cx, Create(cx, typeProto, dataProto, type, nameStr, size, align, ffiType));
    4488          62 :   if (!typeObj)
    4489           0 :     return nullptr;
    4490             : 
    4491             :   // Define the CType as a 'propName' property on 'ctypesObj'.
    4492          62 :   if (!JS_DefineProperty(cx, ctypesObj, propName, typeObj,
    4493             :                          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    4494           0 :     return nullptr;
    4495             : 
    4496          62 :   return typeObj;
    4497             : }
    4498             : 
    4499             : void
    4500           0 : CType::Finalize(JSFreeOp* fop, JSObject* obj)
    4501             : {
    4502             :   // Make sure our TypeCode slot is legit. If it's not, bail.
    4503           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_TYPECODE);
    4504           0 :   if (slot.isUndefined())
    4505           0 :     return;
    4506             : 
    4507             :   // The contents of our slots depends on what kind of type we are.
    4508           0 :   switch (TypeCode(slot.toInt32())) {
    4509             :   case TYPE_function: {
    4510             :     // Free the FunctionInfo.
    4511           0 :     slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
    4512           0 :     if (!slot.isUndefined())
    4513           0 :       FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(slot.toPrivate()));
    4514           0 :     break;
    4515             :   }
    4516             : 
    4517             :   case TYPE_struct: {
    4518             :     // Free the FieldInfoHash table.
    4519           0 :     slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
    4520           0 :     if (!slot.isUndefined()) {
    4521           0 :       void* info = slot.toPrivate();
    4522           0 :       FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
    4523             :     }
    4524             :   }
    4525             : 
    4526             :     MOZ_FALLTHROUGH;
    4527             : 
    4528             :   case TYPE_array: {
    4529             :     // Free the ffi_type info.
    4530           0 :     slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
    4531           0 :     if (!slot.isUndefined()) {
    4532           0 :       ffi_type* ffiType = static_cast<ffi_type*>(slot.toPrivate());
    4533           0 :       FreeOp::get(fop)->free_(ffiType->elements);
    4534           0 :       FreeOp::get(fop)->delete_(ffiType);
    4535             :     }
    4536             : 
    4537           0 :     break;
    4538             :   }
    4539             :   default:
    4540             :     // Nothing to do here.
    4541           0 :     break;
    4542             :   }
    4543             : }
    4544             : 
    4545             : void
    4546           0 : CType::Trace(JSTracer* trc, JSObject* obj)
    4547             : {
    4548             :   // Make sure our TypeCode slot is legit. If it's not, bail.
    4549           0 :   Value slot = obj->as<NativeObject>().getSlot(SLOT_TYPECODE);
    4550           0 :   if (slot.isUndefined())
    4551           0 :     return;
    4552             : 
    4553             :   // The contents of our slots depends on what kind of type we are.
    4554           0 :   switch (TypeCode(slot.toInt32())) {
    4555             :   case TYPE_struct: {
    4556           0 :     slot = obj->as<NativeObject>().getReservedSlot(SLOT_FIELDINFO);
    4557           0 :     if (slot.isUndefined())
    4558           0 :       return;
    4559             : 
    4560           0 :     FieldInfoHash* fields = static_cast<FieldInfoHash*>(slot.toPrivate());
    4561           0 :     fields->trace(trc);
    4562           0 :     break;
    4563             :   }
    4564             :   case TYPE_function: {
    4565             :     // Check if we have a FunctionInfo.
    4566           0 :     slot = obj->as<NativeObject>().getReservedSlot(SLOT_FNINFO);
    4567           0 :     if (slot.isUndefined())
    4568           0 :       return;
    4569             : 
    4570           0 :     FunctionInfo* fninfo = static_cast<FunctionInfo*>(slot.toPrivate());
    4571           0 :     MOZ_ASSERT(fninfo);
    4572             : 
    4573             :     // Identify our objects to the tracer.
    4574           0 :     JS::TraceEdge(trc, &fninfo->mABI, "abi");
    4575           0 :     JS::TraceEdge(trc, &fninfo->mReturnType, "returnType");
    4576           0 :     for (auto& argType : fninfo->mArgTypes)
    4577           0 :       JS::TraceEdge(trc, &argType, "argType");
    4578             : 
    4579           0 :     break;
    4580             :   }
    4581             :   default:
    4582             :     // Nothing to do here.
    4583           0 :     break;
    4584             :   }
    4585             : }
    4586             : 
    4587             : bool
    4588         307 : CType::IsCType(JSObject* obj)
    4589             : {
    4590         307 :   return JS_GetClass(obj) == &sCTypeClass;
    4591             : }
    4592             : 
    4593             : bool
    4594          16 : CType::IsCTypeProto(JSObject* obj)
    4595             : {
    4596          16 :   return JS_GetClass(obj) == &sCTypeProtoClass;
    4597             : }
    4598             : 
    4599             : TypeCode
    4600           6 : CType::GetTypeCode(JSObject* typeObj)
    4601             : {
    4602           6 :   MOZ_ASSERT(IsCType(typeObj));
    4603             : 
    4604           6 :   Value result = JS_GetReservedSlot(typeObj, SLOT_TYPECODE);
    4605           6 :   return TypeCode(result.toInt32());
    4606             : }
    4607             : 
    4608             : bool
    4609           0 : CType::TypesEqual(JSObject* t1, JSObject* t2)
    4610             : {
    4611           0 :   MOZ_ASSERT(IsCType(t1) && IsCType(t2));
    4612             : 
    4613             :   // Fast path: check for object equality.
    4614           0 :   if (t1 == t2)
    4615           0 :     return true;
    4616             : 
    4617             :   // First, perform shallow comparison.
    4618           0 :   TypeCode c1 = GetTypeCode(t1);
    4619           0 :   TypeCode c2 = GetTypeCode(t2);
    4620           0 :   if (c1 != c2)
    4621           0 :     return false;
    4622             : 
    4623             :   // Determine whether the types require shallow or deep comparison.
    4624           0 :   switch (c1) {
    4625             :   case TYPE_pointer: {
    4626             :     // Compare base types.
    4627           0 :     JSObject* b1 = PointerType::GetBaseType(t1);
    4628           0 :     JSObject* b2 = PointerType::GetBaseType(t2);
    4629           0 :     return TypesEqual(b1, b2);
    4630             :   }
    4631             :   case TYPE_function: {
    4632           0 :     FunctionInfo* f1 = FunctionType::GetFunctionInfo(t1);
    4633           0 :     FunctionInfo* f2 = FunctionType::GetFunctionInfo(t2);
    4634             : 
    4635             :     // Compare abi, return type, and argument types.
    4636           0 :     if (f1->mABI != f2->mABI)
    4637           0 :       return false;
    4638             : 
    4639           0 :     if (!TypesEqual(f1->mReturnType, f2->mReturnType))
    4640           0 :       return false;
    4641             : 
    4642           0 :     if (f1->mArgTypes.length() != f2->mArgTypes.length())
    4643           0 :       return false;
    4644             : 
    4645           0 :     if (f1->mIsVariadic != f2->mIsVariadic)
    4646           0 :       return false;
    4647             : 
    4648           0 :     for (size_t i = 0; i < f1->mArgTypes.length(); ++i) {
    4649           0 :       if (!TypesEqual(f1->mArgTypes[i], f2->mArgTypes[i]))
    4650           0 :         return false;
    4651             :     }
    4652             : 
    4653           0 :     return true;
    4654             :   }
    4655             :   case TYPE_array: {
    4656             :     // Compare length, then base types.
    4657             :     // An undefined length array matches other undefined length arrays.
    4658           0 :     size_t s1 = 0, s2 = 0;
    4659           0 :     bool d1 = ArrayType::GetSafeLength(t1, &s1);
    4660           0 :     bool d2 = ArrayType::GetSafeLength(t2, &s2);
    4661           0 :     if (d1 != d2 || (d1 && s1 != s2))
    4662           0 :       return false;
    4663             : 
    4664           0 :     JSObject* b1 = ArrayType::GetBaseType(t1);
    4665           0 :     JSObject* b2 = ArrayType::GetBaseType(t2);
    4666           0 :     return TypesEqual(b1, b2);
    4667             :   }
    4668             :   case TYPE_struct:
    4669             :     // Require exact type object equality.
    4670           0 :     return false;
    4671             :   default:
    4672             :     // Shallow comparison is sufficient.
    4673           0 :     return true;
    4674             :   }
    4675             : }
    4676             : 
    4677             : bool
    4678           0 : CType::GetSafeSize(JSObject* obj, size_t* result)
    4679             : {
    4680           0 :   MOZ_ASSERT(CType::IsCType(obj));
    4681             : 
    4682           0 :   Value size = JS_GetReservedSlot(obj, SLOT_SIZE);
    4683             : 
    4684             :   // The "size" property can be an int, a double, or JS::UndefinedValue()
    4685             :   // (for arrays of undefined length), and must always fit in a size_t.
    4686           0 :   if (size.isInt32()) {
    4687           0 :     *result = size.toInt32();
    4688           0 :     return true;
    4689             :   }
    4690           0 :   if (size.isDouble()) {
    4691           0 :     *result = Convert<size_t>(size.toDouble());
    4692           0 :     return true;
    4693             :   }
    4694             : 
    4695           0 :   MOZ_ASSERT(size.isUndefined());
    4696           0 :   return false;
    4697             : }
    4698             : 
    4699             : size_t
    4700          66 : CType::GetSize(JSObject* obj)
    4701             : {
    4702          66 :   MOZ_ASSERT(CType::IsCType(obj));
    4703             : 
    4704          66 :   Value size = JS_GetReservedSlot(obj, SLOT_SIZE);
    4705             : 
    4706          66 :   MOZ_ASSERT(!size.isUndefined());
    4707             : 
    4708             :   // The "size" property can be an int, a double, or JS::UndefinedValue()
    4709             :   // (for arrays of undefined length), and must always fit in a size_t.
    4710             :   // For callers who know it can never be JS::UndefinedValue(), return a size_t
    4711             :   // directly.
    4712          66 :   if (size.isInt32())
    4713          66 :     return size.toInt32();
    4714           0 :   return Convert<size_t>(size.toDouble());
    4715             : }
    4716             : 
    4717             : bool
    4718          72 : CType::IsSizeDefined(JSObject* obj)
    4719             : {
    4720          72 :   MOZ_ASSERT(CType::IsCType(obj));
    4721             : 
    4722          72 :   Value size = JS_GetReservedSlot(obj, SLOT_SIZE);
    4723             : 
    4724             :   // The "size" property can be an int, a double, or JS::UndefinedValue()
    4725             :   // (for arrays of undefined length), and must always fit in a size_t.
    4726          72 :   MOZ_ASSERT(size.isInt32() || size.isDouble() || size.isUndefined());
    4727          72 :   return !size.isUndefined();
    4728             : }
    4729             : 
    4730             : size_t
    4731          66 : CType::GetAlignment(JSObject* obj)
    4732             : {
    4733          66 :   MOZ_ASSERT(CType::IsCType(obj));
    4734             : 
    4735          66 :   Value slot = JS_GetReservedSlot(obj, SLOT_ALIGN);
    4736          66 :   return static_cast<size_t>(slot.toInt32());
    4737             : }
    4738             : 
    4739             : ffi_type*
    4740           0 : CType::GetFFIType(JSContext* cx, JSObject* obj)
    4741             : {
    4742           0 :   MOZ_ASSERT(CType::IsCType(obj));
    4743             : 
    4744           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
    4745             : 
    4746           0 :   if (!slot.isUndefined()) {
    4747           0 :     return static_cast<ffi_type*>(slot.toPrivate());
    4748             :   }
    4749             : 
    4750           0 :   UniquePtrFFIType result;
    4751           0 :   switch (CType::GetTypeCode(obj)) {
    4752             :   case TYPE_array:
    4753           0 :     result = ArrayType::BuildFFIType(cx, obj);
    4754           0 :     break;
    4755             : 
    4756             :   case TYPE_struct:
    4757           0 :     result = StructType::BuildFFIType(cx, obj);
    4758           0 :     break;
    4759             : 
    4760             :   default:
    4761           0 :     MOZ_CRASH("simple types must have an ffi_type");
    4762             :   }
    4763             : 
    4764           0 :   if (!result)
    4765           0 :     return nullptr;
    4766           0 :   JS_SetReservedSlot(obj, SLOT_FFITYPE, PrivateValue(result.get()));
    4767           0 :   return result.release();
    4768             : }
    4769             : 
    4770             : JSString*
    4771           0 : CType::GetName(JSContext* cx, HandleObject obj)
    4772             : {
    4773           0 :   MOZ_ASSERT(CType::IsCType(obj));
    4774             : 
    4775           0 :   Value string = JS_GetReservedSlot(obj, SLOT_NAME);
    4776           0 :   if (!string.isUndefined())
    4777           0 :     return string.toString();
    4778             : 
    4779             :   // Build the type name lazily.
    4780           0 :   JSString* name = BuildTypeName(cx, obj);
    4781           0 :   if (!name)
    4782           0 :     return nullptr;
    4783           0 :   JS_SetReservedSlot(obj, SLOT_NAME, StringValue(name));
    4784           0 :   return name;
    4785             : }
    4786             : 
    4787             : JSObject*
    4788           4 : CType::GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot)
    4789             : {
    4790             :   // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot
    4791             :   // on the type constructor.
    4792           4 :   Value protoslot = js::GetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO);
    4793           4 :   JSObject* proto = &protoslot.toObject();
    4794           4 :   MOZ_ASSERT(proto);
    4795           4 :   MOZ_ASSERT(CType::IsCTypeProto(proto));
    4796             : 
    4797             :   // Get the desired prototype.
    4798           4 :   Value result = JS_GetReservedSlot(proto, slot);
    4799           4 :   return &result.toObject();
    4800             : }
    4801             : 
    4802             : JSObject*
    4803          12 : CType::GetProtoFromType(JSContext* cx, JSObject* objArg, CTypeProtoSlot slot)
    4804             : {
    4805          12 :   MOZ_ASSERT(IsCType(objArg));
    4806          24 :   RootedObject obj(cx, objArg);
    4807             : 
    4808             :   // Get the prototype of the type object.
    4809          24 :   RootedObject proto(cx);
    4810          12 :   if (!JS_GetPrototype(cx, obj, &proto))
    4811           0 :     return nullptr;
    4812          12 :   MOZ_ASSERT(proto);
    4813          12 :   MOZ_ASSERT(CType::IsCTypeProto(proto));
    4814             : 
    4815             :   // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype.
    4816          12 :   Value result = JS_GetReservedSlot(proto, slot);
    4817          12 :   MOZ_ASSERT(result.isObject());
    4818          12 :   return &result.toObject();
    4819             : }
    4820             : 
    4821             : bool
    4822           0 : CType::IsCTypeOrProto(HandleValue v)
    4823             : {
    4824           0 :   if (!v.isObject())
    4825           0 :     return false;
    4826           0 :   JSObject* obj = &v.toObject();
    4827           0 :   return CType::IsCType(obj) || CType::IsCTypeProto(obj);
    4828             : }
    4829             : 
    4830             : bool
    4831           0 : CType::PrototypeGetter(JSContext* cx, const JS::CallArgs& args)
    4832             : {
    4833           0 :   RootedObject obj(cx, &args.thisv().toObject());
    4834           0 :   unsigned slot = CType::IsCTypeProto(obj) ? (unsigned) SLOT_OURDATAPROTO
    4835           0 :                                            : (unsigned) SLOT_PROTO;
    4836           0 :   args.rval().set(JS_GetReservedSlot(obj, slot));
    4837           0 :   MOZ_ASSERT(args.rval().isObject() || args.rval().isUndefined());
    4838           0 :   return true;
    4839             : }
    4840             : 
    4841             : bool
    4842          85 : CType::IsCType(HandleValue v)
    4843             : {
    4844          85 :   return v.isObject() && CType::IsCType(&v.toObject());
    4845             : }
    4846             : 
    4847             : bool
    4848           0 : CType::NameGetter(JSContext* cx, const JS::CallArgs& args)
    4849             : {
    4850           0 :   RootedObject obj(cx, &args.thisv().toObject());
    4851           0 :   JSString* name = CType::GetName(cx, obj);
    4852           0 :   if (!name)
    4853           0 :     return false;
    4854             : 
    4855           0 :   args.rval().setString(name);
    4856           0 :   return true;
    4857             : }
    4858             : 
    4859             : bool
    4860          76 : CType::SizeGetter(JSContext* cx, const JS::CallArgs& args)
    4861             : {
    4862         152 :   RootedObject obj(cx, &args.thisv().toObject());
    4863          76 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_SIZE));
    4864          76 :   MOZ_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
    4865         152 :   return true;
    4866             : }
    4867             : 
    4868             : bool
    4869           9 : CType::PtrGetter(JSContext* cx, const JS::CallArgs& args)
    4870             : {
    4871          18 :   RootedObject obj(cx, &args.thisv().toObject());
    4872           9 :   JSObject* pointerType = PointerType::CreateInternal(cx, obj);
    4873           9 :   if (!pointerType)
    4874           0 :     return false;
    4875             : 
    4876           9 :   args.rval().setObject(*pointerType);
    4877           9 :   return true;
    4878             : }
    4879             : 
    4880             : bool
    4881           0 : CType::CreateArray(JSContext* cx, unsigned argc, Value* vp)
    4882             : {
    4883           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    4884           0 :   RootedObject baseType(cx, JS_THIS_OBJECT(cx, vp));
    4885           0 :   if (!baseType)
    4886           0 :     return false;
    4887           0 :   if (!CType::IsCType(baseType)) {
    4888           0 :     return IncompatibleThisProto(cx, "CType.prototype.array", args.thisv());
    4889             :   }
    4890             : 
    4891             :   // Construct and return a new ArrayType object.
    4892           0 :   if (args.length() > 1) {
    4893           0 :     return ArgumentLengthError(cx, "CType.prototype.array", "at most one", "");
    4894             :   }
    4895             : 
    4896             :   // Convert the length argument to a size_t.
    4897           0 :   size_t length = 0;
    4898           0 :   if (args.length() == 1 && !jsvalToSize(cx, args[0], false, &length)) {
    4899           0 :     return ArgumentTypeMismatch(cx, "", "CType.prototype.array",
    4900           0 :                                 "a nonnegative integer");
    4901             :   }
    4902             : 
    4903           0 :   JSObject* result = ArrayType::CreateInternal(cx, baseType, length, args.length() == 1);
    4904           0 :   if (!result)
    4905           0 :     return false;
    4906             : 
    4907           0 :   args.rval().setObject(*result);
    4908           0 :   return true;
    4909             : }
    4910             : 
    4911             : bool
    4912           0 : CType::ToString(JSContext* cx, unsigned argc, Value* vp)
    4913             : {
    4914           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    4915           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    4916           0 :   if (!obj)
    4917           0 :     return false;
    4918           0 :   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
    4919           0 :     return IncompatibleThisProto(cx, "CType.prototype.toString",
    4920           0 :                                  InformalValueTypeName(args.thisv()));
    4921             :   }
    4922             : 
    4923             :   // Create the appropriate string depending on whether we're sCTypeClass or
    4924             :   // sCTypeProtoClass.
    4925             :   JSString* result;
    4926           0 :   if (CType::IsCType(obj)) {
    4927           0 :     AutoString type;
    4928           0 :     AppendString(type, "type ");
    4929           0 :     AppendString(type, GetName(cx, obj));
    4930           0 :     result = NewUCString(cx, type);
    4931             :   }
    4932             :   else {
    4933           0 :     result = JS_NewStringCopyZ(cx, "[CType proto object]");
    4934             :   }
    4935           0 :   if (!result)
    4936           0 :     return false;
    4937             : 
    4938           0 :   args.rval().setString(result);
    4939           0 :   return true;
    4940             : }
    4941             : 
    4942             : bool
    4943           0 : CType::ToSource(JSContext* cx, unsigned argc, Value* vp)
    4944             : {
    4945           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    4946           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    4947           0 :   if (!obj)
    4948           0 :     return false;
    4949           0 :   if (!CType::IsCType(obj) && !CType::IsCTypeProto(obj)) {
    4950           0 :     return IncompatibleThisProto(cx, "CType.prototype.toSource",
    4951           0 :                                  InformalValueTypeName(args.thisv()));
    4952             :   }
    4953             : 
    4954             :   // Create the appropriate string depending on whether we're sCTypeClass or
    4955             :   // sCTypeProtoClass.
    4956             :   JSString* result;
    4957           0 :   if (CType::IsCType(obj)) {
    4958           0 :     AutoString source;
    4959           0 :     BuildTypeSource(cx, obj, false, source);
    4960           0 :     result = NewUCString(cx, source);
    4961             :   } else {
    4962           0 :     result = JS_NewStringCopyZ(cx, "[CType proto object]");
    4963             :   }
    4964           0 :   if (!result)
    4965           0 :     return false;
    4966             : 
    4967           0 :   args.rval().setString(result);
    4968           0 :   return true;
    4969             : }
    4970             : 
    4971             : bool
    4972           0 : CType::HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
    4973             : {
    4974           0 :   MOZ_ASSERT(CType::IsCType(obj));
    4975             : 
    4976           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_PROTO);
    4977           0 :   JS::Rooted<JSObject*> prototype(cx, &slot.toObject());
    4978           0 :   MOZ_ASSERT(prototype);
    4979           0 :   MOZ_ASSERT(CData::IsCDataProto(prototype));
    4980             : 
    4981           0 :   *bp = false;
    4982           0 :   if (v.isPrimitive())
    4983           0 :     return true;
    4984             : 
    4985           0 :   RootedObject proto(cx, &v.toObject());
    4986             :   for (;;) {
    4987           0 :     if (!JS_GetPrototype(cx, proto, &proto))
    4988           0 :       return false;
    4989           0 :     if (!proto)
    4990           0 :       break;
    4991           0 :     if (proto == prototype) {
    4992           0 :       *bp = true;
    4993           0 :       break;
    4994             :     }
    4995             :   }
    4996           0 :   return true;
    4997             : }
    4998             : 
    4999             : static JSObject*
    5000           0 : CType::GetGlobalCTypes(JSContext* cx, JSObject* objArg)
    5001             : {
    5002           0 :   MOZ_ASSERT(CType::IsCType(objArg));
    5003             : 
    5004           0 :   RootedObject obj(cx, objArg);
    5005           0 :   RootedObject objTypeProto(cx);
    5006           0 :   if (!JS_GetPrototype(cx, obj, &objTypeProto))
    5007           0 :     return nullptr;
    5008           0 :   MOZ_ASSERT(objTypeProto);
    5009           0 :   MOZ_ASSERT(CType::IsCTypeProto(objTypeProto));
    5010             : 
    5011           0 :   Value valCTypes = JS_GetReservedSlot(objTypeProto, SLOT_CTYPES);
    5012           0 :   MOZ_ASSERT(valCTypes.isObject());
    5013           0 :   return &valCTypes.toObject();
    5014             : }
    5015             : 
    5016             : /*******************************************************************************
    5017             : ** ABI implementation
    5018             : *******************************************************************************/
    5019             : 
    5020             : bool
    5021           0 : ABI::IsABI(JSObject* obj)
    5022             : {
    5023           0 :   return JS_GetClass(obj) == &sCABIClass;
    5024             : }
    5025             : 
    5026             : bool
    5027           0 : ABI::ToSource(JSContext* cx, unsigned argc, Value* vp)
    5028             : {
    5029           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5030           0 :   if (args.length() != 0) {
    5031           0 :     return ArgumentLengthError(cx, "ABI.prototype.toSource", "no", "s");
    5032             :   }
    5033             : 
    5034           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    5035           0 :   if (!obj)
    5036           0 :     return false;
    5037           0 :   if (!ABI::IsABI(obj)) {
    5038           0 :     return IncompatibleThisProto(cx, "ABI.prototype.toSource",
    5039           0 :                                  InformalValueTypeName(args.thisv()));
    5040             :   }
    5041             : 
    5042             :   JSString* result;
    5043           0 :   switch (GetABICode(obj)) {
    5044             :     case ABI_DEFAULT:
    5045           0 :       result = JS_NewStringCopyZ(cx, "ctypes.default_abi");
    5046           0 :       break;
    5047             :     case ABI_STDCALL:
    5048           0 :       result = JS_NewStringCopyZ(cx, "ctypes.stdcall_abi");
    5049           0 :       break;
    5050             :     case ABI_THISCALL:
    5051           0 :       result = JS_NewStringCopyZ(cx, "ctypes.thiscall_abi");
    5052           0 :       break;
    5053             :     case ABI_WINAPI:
    5054           0 :       result = JS_NewStringCopyZ(cx, "ctypes.winapi_abi");
    5055           0 :       break;
    5056             :     default:
    5057           0 :       JS_ReportErrorASCII(cx, "not a valid ABICode");
    5058           0 :       return false;
    5059             :   }
    5060           0 :   if (!result)
    5061           0 :     return false;
    5062             : 
    5063           0 :   args.rval().setString(result);
    5064           0 :   return true;
    5065             : }
    5066             : 
    5067             : 
    5068             : /*******************************************************************************
    5069             : ** PointerType implementation
    5070             : *******************************************************************************/
    5071             : 
    5072             : bool
    5073           0 : PointerType::Create(JSContext* cx, unsigned argc, Value* vp)
    5074             : {
    5075           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5076             :   // Construct and return a new PointerType object.
    5077           0 :   if (args.length() != 1) {
    5078           0 :     return ArgumentLengthError(cx, "PointerType", "one", "");
    5079             :   }
    5080             : 
    5081           0 :   Value arg = args[0];
    5082           0 :   RootedObject obj(cx);
    5083           0 :   if (arg.isPrimitive() || !CType::IsCType(obj = &arg.toObject())) {
    5084           0 :     return ArgumentTypeMismatch(cx, "", "PointerType", "a CType");
    5085             :   }
    5086             : 
    5087           0 :   JSObject* result = CreateInternal(cx, obj);
    5088           0 :   if (!result)
    5089           0 :     return false;
    5090             : 
    5091           0 :   args.rval().setObject(*result);
    5092           0 :   return true;
    5093             : }
    5094             : 
    5095             : JSObject*
    5096          11 : PointerType::CreateInternal(JSContext* cx, HandleObject baseType)
    5097             : {
    5098             :   // check if we have a cached PointerType on our base CType.
    5099          11 :   Value slot = JS_GetReservedSlot(baseType, SLOT_PTR);
    5100          11 :   if (!slot.isUndefined())
    5101           5 :     return &slot.toObject();
    5102             : 
    5103             :   // Get ctypes.PointerType.prototype and the common prototype for CData objects
    5104             :   // of this type, or ctypes.FunctionType.prototype for function pointers.
    5105           6 :   CTypeProtoSlot slotId = CType::GetTypeCode(baseType) == TYPE_function ?
    5106           6 :     SLOT_FUNCTIONDATAPROTO : SLOT_POINTERDATAPROTO;
    5107          12 :   RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, slotId));
    5108           6 :   if (!dataProto)
    5109           0 :     return nullptr;
    5110          12 :   RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO));
    5111           6 :   if (!typeProto)
    5112           0 :     return nullptr;
    5113             : 
    5114             :   // Create a new CType object with the common properties and slots.
    5115          12 :   RootedValue sizeVal(cx, Int32Value(sizeof(void*)));
    5116          12 :   RootedValue alignVal(cx, Int32Value(ffi_type_pointer.alignment));
    5117          12 :   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer,
    5118             :                                     nullptr, sizeVal, alignVal,
    5119           6 :                                     &ffi_type_pointer);
    5120           6 :   if (!typeObj)
    5121           0 :     return nullptr;
    5122             : 
    5123             :   // Set the target type. (This will be 'null' for an opaque pointer type.)
    5124           6 :   JS_SetReservedSlot(typeObj, SLOT_TARGET_T, ObjectValue(*baseType));
    5125             : 
    5126             :   // Finally, cache our newly-created PointerType on our pointed-to CType.
    5127           6 :   JS_SetReservedSlot(baseType, SLOT_PTR, ObjectValue(*typeObj));
    5128             : 
    5129           6 :   return typeObj;
    5130             : }
    5131             : 
    5132             : bool
    5133           0 : PointerType::ConstructData(JSContext* cx,
    5134             :                            HandleObject obj,
    5135             :                            const CallArgs& args)
    5136             : {
    5137           0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_pointer) {
    5138           0 :     return IncompatibleCallee(cx, "PointerType constructor", obj);
    5139             :   }
    5140             : 
    5141           0 :   if (args.length() > 3) {
    5142           0 :     return ArgumentLengthError(cx, "PointerType constructor", "0, 1, 2, or 3",
    5143           0 :                                "s");
    5144             :   }
    5145             : 
    5146           0 :   RootedObject result(cx, CData::Create(cx, obj, nullptr, nullptr, true));
    5147           0 :   if (!result)
    5148           0 :     return false;
    5149             : 
    5150             :   // Set return value early, must not observe *vp after
    5151           0 :   args.rval().setObject(*result);
    5152             : 
    5153             :   // There are 3 things that we might be creating here:
    5154             :   // 1 - A null pointer (no arguments)
    5155             :   // 2 - An initialized pointer (1 argument)
    5156             :   // 3 - A closure (1-3 arguments)
    5157             :   //
    5158             :   // The API doesn't give us a perfect way to distinguish 2 and 3, but the
    5159             :   // heuristics we use should be fine.
    5160             : 
    5161             :   //
    5162             :   // Case 1 - Null pointer
    5163             :   //
    5164           0 :   if (args.length() == 0)
    5165           0 :     return true;
    5166             : 
    5167             :   // Analyze the arguments a bit to decide what to do next.
    5168           0 :   RootedObject baseObj(cx, PointerType::GetBaseType(obj));
    5169           0 :   bool looksLikeClosure = CType::GetTypeCode(baseObj) == TYPE_function &&
    5170           0 :                           args[0].isObject() && JS::IsCallable(&args[0].toObject());
    5171             : 
    5172             :   //
    5173             :   // Case 2 - Initialized pointer
    5174             :   //
    5175           0 :   if (!looksLikeClosure) {
    5176           0 :     if (args.length() != 1) {
    5177           0 :       return ArgumentLengthError(cx, "FunctionType constructor", "one", "");
    5178             :     }
    5179           0 :     return ExplicitConvert(cx, args[0], obj, CData::GetData(result),
    5180           0 :                            ConversionType::Construct);
    5181             :   }
    5182             : 
    5183             :   //
    5184             :   // Case 3 - Closure
    5185             :   //
    5186             : 
    5187             :   // The second argument is an optional 'this' parameter with which to invoke
    5188             :   // the given js function. Callers may leave this blank, or pass null if they
    5189             :   // wish to pass the third argument.
    5190           0 :   RootedObject thisObj(cx, nullptr);
    5191           0 :   if (args.length() >= 2) {
    5192           0 :     if (args[1].isNull()) {
    5193           0 :       thisObj = nullptr;
    5194           0 :     } else if (args[1].isObject()) {
    5195           0 :       thisObj = &args[1].toObject();
    5196           0 :     } else if (!JS_ValueToObject(cx, args[1], &thisObj)) {
    5197           0 :       return false;
    5198             :     }
    5199             :   }
    5200             : 
    5201             :   // The third argument is an optional error sentinel that js-ctypes will return
    5202             :   // if an exception is raised while executing the closure. The type must match
    5203             :   // the return type of the callback.
    5204           0 :   RootedValue errVal(cx);
    5205           0 :   if (args.length() == 3)
    5206           0 :     errVal = args[2];
    5207             : 
    5208           0 :   RootedObject fnObj(cx, &args[0].toObject());
    5209           0 :   return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj, errVal);
    5210             : }
    5211             : 
    5212             : JSObject*
    5213           0 : PointerType::GetBaseType(JSObject* obj)
    5214             : {
    5215           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_pointer);
    5216             : 
    5217           0 :   Value type = JS_GetReservedSlot(obj, SLOT_TARGET_T);
    5218           0 :   MOZ_ASSERT(!type.isNull());
    5219           0 :   return &type.toObject();
    5220             : }
    5221             : 
    5222             : bool
    5223           0 : PointerType::IsPointerType(HandleValue v)
    5224             : {
    5225           0 :   if (!v.isObject())
    5226           0 :     return false;
    5227           0 :   JSObject* obj = &v.toObject();
    5228           0 :   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_pointer;
    5229             : }
    5230             : 
    5231             : bool
    5232           0 : PointerType::IsPointer(HandleValue v)
    5233             : {
    5234           0 :   if (!v.isObject())
    5235           0 :     return false;
    5236           0 :   JSObject* obj = &v.toObject();
    5237           0 :   return CData::IsCData(obj) && CType::GetTypeCode(CData::GetCType(obj)) == TYPE_pointer;
    5238             : }
    5239             : 
    5240             : bool
    5241           0 : PointerType::TargetTypeGetter(JSContext* cx, const JS::CallArgs& args)
    5242             : {
    5243           0 :   RootedObject obj(cx, &args.thisv().toObject());
    5244           0 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_TARGET_T));
    5245           0 :   MOZ_ASSERT(args.rval().isObject());
    5246           0 :   return true;
    5247             : }
    5248             : 
    5249             : bool
    5250           0 : PointerType::IsNull(JSContext* cx, unsigned argc, Value* vp)
    5251             : {
    5252           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5253           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    5254           0 :   if (!obj)
    5255           0 :     return false;
    5256           0 :   if (!CData::IsCData(obj)) {
    5257           0 :     return IncompatibleThisProto(cx, "PointerType.prototype.isNull",
    5258           0 :                                  args.thisv());
    5259             :   }
    5260             : 
    5261             :   // Get pointer type and base type.
    5262           0 :   JSObject* typeObj = CData::GetCType(obj);
    5263           0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    5264           0 :     return IncompatibleThisType(cx, "PointerType.prototype.isNull",
    5265           0 :                                 "non-PointerType CData", args.thisv());
    5266             :   }
    5267             : 
    5268           0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    5269           0 :   args.rval().setBoolean(data == nullptr);
    5270           0 :   return true;
    5271             : }
    5272             : 
    5273             : bool
    5274           0 : PointerType::OffsetBy(JSContext* cx, const CallArgs& args, int offset)
    5275             : {
    5276           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, args.base()));
    5277           0 :   if (!obj)
    5278           0 :     return false;
    5279           0 :   if (!CData::IsCData(obj)) {
    5280           0 :     if (offset == 1) {
    5281           0 :       return IncompatibleThisProto(cx, "PointerType.prototype.increment",
    5282           0 :                                    args.thisv());
    5283             :     }
    5284           0 :     return IncompatibleThisProto(cx, "PointerType.prototype.decrement",
    5285           0 :                                  args.thisv());
    5286             :   }
    5287             : 
    5288           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    5289           0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    5290           0 :     if (offset == 1) {
    5291           0 :       return IncompatibleThisType(cx, "PointerType.prototype.increment",
    5292           0 :                                   "non-PointerType CData", args.thisv());
    5293             :     }
    5294           0 :     return IncompatibleThisType(cx, "PointerType.prototype.decrement",
    5295           0 :                                 "non-PointerType CData", args.thisv());
    5296             :   }
    5297             : 
    5298           0 :   RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
    5299           0 :   if (!CType::IsSizeDefined(baseType)) {
    5300           0 :     return UndefinedSizePointerError(cx, "modify", obj);
    5301             :   }
    5302             : 
    5303           0 :   size_t elementSize = CType::GetSize(baseType);
    5304           0 :   char* data = static_cast<char*>(*static_cast<void**>(CData::GetData(obj)));
    5305           0 :   void* address = data + offset * elementSize;
    5306             : 
    5307             :   // Create a PointerType CData object containing the new address.
    5308           0 :   JSObject* result = CData::Create(cx, typeObj, nullptr, &address, true);
    5309           0 :   if (!result)
    5310           0 :     return false;
    5311             : 
    5312           0 :   args.rval().setObject(*result);
    5313           0 :   return true;
    5314             : }
    5315             : 
    5316             : bool
    5317           0 : PointerType::Increment(JSContext* cx, unsigned argc, Value* vp)
    5318             : {
    5319           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5320           0 :   return OffsetBy(cx, args, 1);
    5321             : }
    5322             : 
    5323             : bool
    5324           0 : PointerType::Decrement(JSContext* cx, unsigned argc, Value* vp)
    5325             : {
    5326           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5327           0 :   return OffsetBy(cx, args, -1);
    5328             : }
    5329             : 
    5330             : bool
    5331           0 : PointerType::ContentsGetter(JSContext* cx, const JS::CallArgs& args)
    5332             : {
    5333           0 :   RootedObject obj(cx, &args.thisv().toObject());
    5334           0 :   RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
    5335           0 :   if (!CType::IsSizeDefined(baseType)) {
    5336           0 :     return UndefinedSizePointerError(cx, "get contents of", obj);
    5337             :   }
    5338             : 
    5339           0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    5340           0 :   if (data == nullptr) {
    5341           0 :     return NullPointerError(cx, "read contents of", obj);
    5342             :   }
    5343             : 
    5344           0 :   RootedValue result(cx);
    5345           0 :   if (!ConvertToJS(cx, baseType, nullptr, data, false, false, &result))
    5346           0 :     return false;
    5347             : 
    5348           0 :   args.rval().set(result);
    5349           0 :   return true;
    5350             : }
    5351             : 
    5352             : bool
    5353           0 : PointerType::ContentsSetter(JSContext* cx, const JS::CallArgs& args)
    5354             : {
    5355           0 :   RootedObject obj(cx, &args.thisv().toObject());
    5356           0 :   RootedObject baseType(cx, GetBaseType(CData::GetCType(obj)));
    5357           0 :   if (!CType::IsSizeDefined(baseType)) {
    5358           0 :     return UndefinedSizePointerError(cx, "set contents of", obj);
    5359             :   }
    5360             : 
    5361           0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    5362           0 :   if (data == nullptr) {
    5363           0 :     return NullPointerError(cx, "write contents to", obj);
    5364             :   }
    5365             : 
    5366           0 :   args.rval().setUndefined();
    5367           0 :   return ImplicitConvert(cx, args.get(0), baseType, data,
    5368           0 :                          ConversionType::Setter, nullptr);
    5369             : }
    5370             : 
    5371             : /*******************************************************************************
    5372             : ** ArrayType implementation
    5373             : *******************************************************************************/
    5374             : 
    5375             : bool
    5376           0 : ArrayType::Create(JSContext* cx, unsigned argc, Value* vp)
    5377             : {
    5378           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5379             :   // Construct and return a new ArrayType object.
    5380           0 :   if (args.length() < 1 || args.length() > 2) {
    5381           0 :     return ArgumentLengthError(cx, "ArrayType", "one or two", "s");
    5382             :   }
    5383             : 
    5384           0 :   if (args[0].isPrimitive() || !CType::IsCType(&args[0].toObject())) {
    5385           0 :     return ArgumentTypeMismatch(cx, "first ", "ArrayType", "a CType");
    5386             :   }
    5387             : 
    5388             :   // Convert the length argument to a size_t.
    5389           0 :   size_t length = 0;
    5390           0 :   if (args.length() == 2 && !jsvalToSize(cx, args[1], false, &length)) {
    5391           0 :     return ArgumentTypeMismatch(cx, "second ", "ArrayType",
    5392           0 :                                 "a nonnegative integer");
    5393             :   }
    5394             : 
    5395           0 :   RootedObject baseType(cx, &args[0].toObject());
    5396           0 :   JSObject* result = CreateInternal(cx, baseType, length, args.length() == 2);
    5397           0 :   if (!result)
    5398           0 :     return false;
    5399             : 
    5400           0 :   args.rval().setObject(*result);
    5401           0 :   return true;
    5402             : }
    5403             : 
    5404             : JSObject*
    5405           0 : ArrayType::CreateInternal(JSContext* cx,
    5406             :                           HandleObject baseType,
    5407             :                           size_t length,
    5408             :                           bool lengthDefined)
    5409             : {
    5410             :   // Get ctypes.ArrayType.prototype and the common prototype for CData objects
    5411             :   // of this type, from ctypes.CType.prototype.
    5412           0 :   RootedObject typeProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYPROTO));
    5413           0 :   if (!typeProto)
    5414           0 :     return nullptr;
    5415           0 :   RootedObject dataProto(cx, CType::GetProtoFromType(cx, baseType, SLOT_ARRAYDATAPROTO));
    5416           0 :   if (!dataProto)
    5417           0 :     return nullptr;
    5418             : 
    5419             :   // Determine the size of the array from the base type, if possible.
    5420             :   // The size of the base type must be defined.
    5421             :   // If our length is undefined, both our size and length will be undefined.
    5422             :   size_t baseSize;
    5423           0 :   if (!CType::GetSafeSize(baseType, &baseSize)) {
    5424           0 :     JS_ReportErrorASCII(cx, "base size must be defined");
    5425           0 :     return nullptr;
    5426             :   }
    5427             : 
    5428           0 :   RootedValue sizeVal(cx);
    5429           0 :   RootedValue lengthVal(cx);
    5430           0 :   if (lengthDefined) {
    5431             :     // Check for overflow, and convert to an int or double as required.
    5432           0 :     size_t size = length * baseSize;
    5433           0 :     if (length > 0 && size / length != baseSize) {
    5434           0 :       SizeOverflow(cx, "array size", "size_t");
    5435           0 :       return nullptr;
    5436             :     }
    5437           0 :     if (!SizeTojsval(cx, size, &sizeVal)) {
    5438           0 :       SizeOverflow(cx, "array size", "JavaScript number");
    5439           0 :       return nullptr;
    5440             :     }
    5441           0 :     if (!SizeTojsval(cx, length, &lengthVal)) {
    5442           0 :       SizeOverflow(cx, "array length", "JavaScript number");
    5443           0 :       return nullptr;
    5444             :     }
    5445             :   }
    5446             : 
    5447           0 :   RootedValue alignVal(cx, Int32Value(CType::GetAlignment(baseType)));
    5448             : 
    5449             :   // Create a new CType object with the common properties and slots.
    5450           0 :   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_array, nullptr,
    5451           0 :                                     sizeVal, alignVal, nullptr);
    5452           0 :   if (!typeObj)
    5453           0 :     return nullptr;
    5454             : 
    5455             :   // Set the element type.
    5456           0 :   JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, ObjectValue(*baseType));
    5457             : 
    5458             :   // Set the length.
    5459           0 :   JS_SetReservedSlot(typeObj, SLOT_LENGTH, lengthVal);
    5460             : 
    5461           0 :   return typeObj;
    5462             : }
    5463             : 
    5464             : bool
    5465           0 : ArrayType::ConstructData(JSContext* cx,
    5466             :                          HandleObject obj_,
    5467             :                          const CallArgs& args)
    5468             : {
    5469           0 :   RootedObject obj(cx, obj_); // Make a mutable version
    5470             : 
    5471           0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
    5472           0 :     return IncompatibleCallee(cx, "ArrayType constructor", obj);
    5473             :   }
    5474             : 
    5475             :   // Decide whether we have an object to initialize from. We'll override this
    5476             :   // if we get a length argument instead.
    5477           0 :   bool convertObject = args.length() == 1;
    5478             : 
    5479             :   // Check if we're an array of undefined length. If we are, allow construction
    5480             :   // with a length argument, or with an actual JS array.
    5481           0 :   if (CType::IsSizeDefined(obj)) {
    5482           0 :     if (args.length() > 1) {
    5483           0 :       return ArgumentLengthError(cx, "size defined ArrayType constructor",
    5484           0 :                                  "at most one", "");
    5485             :     }
    5486             : 
    5487             :   } else {
    5488           0 :     if (args.length() != 1) {
    5489           0 :       return ArgumentLengthError(cx, "size undefined ArrayType constructor",
    5490           0 :                                  "one", "");
    5491             :     }
    5492             : 
    5493           0 :     RootedObject baseType(cx, GetBaseType(obj));
    5494             : 
    5495             :     size_t length;
    5496           0 :     if (jsvalToSize(cx, args[0], false, &length)) {
    5497             :       // Have a length, rather than an object to initialize from.
    5498           0 :       convertObject = false;
    5499             : 
    5500           0 :     } else if (args[0].isObject()) {
    5501             :       // We were given an object with a .length property.
    5502             :       // This could be a JS array, or a CData array.
    5503           0 :       RootedObject arg(cx, &args[0].toObject());
    5504           0 :       RootedValue lengthVal(cx);
    5505           0 :       if (!JS_GetProperty(cx, arg, "length", &lengthVal) ||
    5506           0 :           !jsvalToSize(cx, lengthVal, false, &length)) {
    5507           0 :         return ArgumentTypeMismatch(cx, "",
    5508             :                                     "size undefined ArrayType constructor",
    5509           0 :                                     "an array object or integer");
    5510             :       }
    5511             : 
    5512           0 :     } else if (args[0].isString()) {
    5513             :       // We were given a string. Size the array to the appropriate length,
    5514             :       // including space for the terminator.
    5515           0 :       JSString* sourceString = args[0].toString();
    5516           0 :       size_t sourceLength = sourceString->length();
    5517           0 :       JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
    5518           0 :       if (!sourceLinear)
    5519           0 :         return false;
    5520             : 
    5521           0 :       switch (CType::GetTypeCode(baseType)) {
    5522             :       case TYPE_char:
    5523             :       case TYPE_signed_char:
    5524             :       case TYPE_unsigned_char: {
    5525             :         // Determine the UTF-8 length.
    5526           0 :         length = GetDeflatedUTF8StringLength(cx, sourceLinear);
    5527           0 :         if (length == (size_t) -1)
    5528           0 :           return false;
    5529             : 
    5530           0 :         ++length;
    5531           0 :         break;
    5532             :       }
    5533             :       case TYPE_char16_t:
    5534           0 :         length = sourceLength + 1;
    5535           0 :         break;
    5536             :       default:
    5537           0 :         return ConvError(cx, obj, args[0], ConversionType::Construct);
    5538             :       }
    5539             : 
    5540             :     } else {
    5541           0 :       return ArgumentTypeMismatch(cx, "",
    5542             :                                   "size undefined ArrayType constructor",
    5543           0 :                                   "an array object or integer");
    5544             :     }
    5545             : 
    5546             :     // Construct a new ArrayType of defined length, for the new CData object.
    5547           0 :     obj = CreateInternal(cx, baseType, length, true);
    5548           0 :     if (!obj)
    5549           0 :       return false;
    5550             :   }
    5551             : 
    5552           0 :   JSObject* result = CData::Create(cx, obj, nullptr, nullptr, true);
    5553           0 :   if (!result)
    5554           0 :     return false;
    5555             : 
    5556           0 :   args.rval().setObject(*result);
    5557             : 
    5558           0 :   if (convertObject) {
    5559           0 :     if (!ExplicitConvert(cx, args[0], obj, CData::GetData(result),
    5560             :                          ConversionType::Construct))
    5561           0 :       return false;
    5562             :   }
    5563             : 
    5564           0 :   return true;
    5565             : }
    5566             : 
    5567             : JSObject*
    5568           0 : ArrayType::GetBaseType(JSObject* obj)
    5569             : {
    5570           0 :   MOZ_ASSERT(CType::IsCType(obj));
    5571           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    5572             : 
    5573           0 :   Value type = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
    5574           0 :   MOZ_ASSERT(!type.isNull());
    5575           0 :   return &type.toObject();
    5576             : }
    5577             : 
    5578             : bool
    5579           0 : ArrayType::GetSafeLength(JSObject* obj, size_t* result)
    5580             : {
    5581           0 :   MOZ_ASSERT(CType::IsCType(obj));
    5582           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    5583             : 
    5584           0 :   Value length = JS_GetReservedSlot(obj, SLOT_LENGTH);
    5585             : 
    5586             :   // The "length" property can be an int, a double, or JS::UndefinedValue()
    5587             :   // (for arrays of undefined length), and must always fit in a size_t.
    5588           0 :   if (length.isInt32()) {
    5589           0 :     *result = length.toInt32();
    5590           0 :     return true;
    5591             :   }
    5592           0 :   if (length.isDouble()) {
    5593           0 :     *result = Convert<size_t>(length.toDouble());
    5594           0 :     return true;
    5595             :   }
    5596             : 
    5597           0 :   MOZ_ASSERT(length.isUndefined());
    5598           0 :   return false;
    5599             : }
    5600             : 
    5601             : size_t
    5602           0 : ArrayType::GetLength(JSObject* obj)
    5603             : {
    5604           0 :   MOZ_ASSERT(CType::IsCType(obj));
    5605           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    5606             : 
    5607           0 :   Value length = JS_GetReservedSlot(obj, SLOT_LENGTH);
    5608             : 
    5609           0 :   MOZ_ASSERT(!length.isUndefined());
    5610             : 
    5611             :   // The "length" property can be an int, a double, or JS::UndefinedValue()
    5612             :   // (for arrays of undefined length), and must always fit in a size_t.
    5613             :   // For callers who know it can never be JS::UndefinedValue(), return a size_t
    5614             :   // directly.
    5615           0 :   if (length.isInt32())
    5616           0 :     return length.toInt32();
    5617           0 :   return Convert<size_t>(length.toDouble());
    5618             : }
    5619             : 
    5620             : UniquePtrFFIType
    5621           0 : ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
    5622             : {
    5623           0 :   MOZ_ASSERT(CType::IsCType(obj));
    5624           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    5625           0 :   MOZ_ASSERT(CType::IsSizeDefined(obj));
    5626             : 
    5627           0 :   JSObject* baseType = ArrayType::GetBaseType(obj);
    5628           0 :   ffi_type* ffiBaseType = CType::GetFFIType(cx, baseType);
    5629           0 :   if (!ffiBaseType)
    5630           0 :     return nullptr;
    5631             : 
    5632           0 :   size_t length = ArrayType::GetLength(obj);
    5633             : 
    5634             :   // Create an ffi_type to represent the array. This is necessary for the case
    5635             :   // where the array is part of a struct. Since libffi has no intrinsic
    5636             :   // support for array types, we approximate it by creating a struct type
    5637             :   // with elements of type 'baseType' and with appropriate size and alignment
    5638             :   // values. It would be nice to not do all the work of setting up 'elements',
    5639             :   // but some libffi platforms currently require that it be meaningful. I'm
    5640             :   // looking at you, x86_64.
    5641           0 :   auto ffiType = cx->make_unique<ffi_type>();
    5642           0 :   if (!ffiType) {
    5643           0 :     JS_ReportOutOfMemory(cx);
    5644           0 :     return nullptr;
    5645             :   }
    5646             : 
    5647           0 :   ffiType->type = FFI_TYPE_STRUCT;
    5648           0 :   ffiType->size = CType::GetSize(obj);
    5649           0 :   ffiType->alignment = CType::GetAlignment(obj);
    5650           0 :   ffiType->elements = cx->pod_malloc<ffi_type*>(length + 1);
    5651           0 :   if (!ffiType->elements) {
    5652           0 :     JS_ReportAllocationOverflow(cx);
    5653           0 :     return nullptr;
    5654             :   }
    5655             : 
    5656           0 :   for (size_t i = 0; i < length; ++i)
    5657           0 :     ffiType->elements[i] = ffiBaseType;
    5658           0 :   ffiType->elements[length] = nullptr;
    5659             : 
    5660           0 :   return Move(ffiType);
    5661             : }
    5662             : 
    5663             : bool
    5664           0 : ArrayType::IsArrayType(HandleValue v)
    5665             : {
    5666           0 :   if (!v.isObject())
    5667           0 :     return false;
    5668           0 :   JSObject* obj = &v.toObject();
    5669           0 :   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
    5670             : }
    5671             : 
    5672             : bool
    5673           0 : ArrayType::IsArrayOrArrayType(HandleValue v)
    5674             : {
    5675           0 :   if (!v.isObject())
    5676           0 :     return false;
    5677           0 :   JSObject* obj = &v.toObject();
    5678             : 
    5679             :    // Allow both CTypes and CDatas of the ArrayType persuasion by extracting the
    5680             :    // CType if we're dealing with a CData.
    5681           0 :   if (CData::IsCData(obj)) {
    5682           0 :     obj = CData::GetCType(obj);
    5683             :   }
    5684           0 :   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_array;
    5685             : }
    5686             : 
    5687             : bool
    5688           0 : ArrayType::ElementTypeGetter(JSContext* cx, const JS::CallArgs& args)
    5689             : {
    5690           0 :   RootedObject obj(cx, &args.thisv().toObject());
    5691           0 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_ELEMENT_T));
    5692           0 :   MOZ_ASSERT(args.rval().isObject());
    5693           0 :   return true;
    5694             : }
    5695             : 
    5696             : bool
    5697           0 : ArrayType::LengthGetter(JSContext* cx, const JS::CallArgs& args)
    5698             : {
    5699           0 :   JSObject* obj = &args.thisv().toObject();
    5700             : 
    5701             :   // This getter exists for both CTypes and CDatas of the ArrayType persuasion.
    5702             :   // If we're dealing with a CData, get the CType from it.
    5703           0 :   if (CData::IsCData(obj))
    5704           0 :     obj = CData::GetCType(obj);
    5705             : 
    5706           0 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_LENGTH));
    5707           0 :   MOZ_ASSERT(args.rval().isNumber() || args.rval().isUndefined());
    5708           0 :   return true;
    5709             : }
    5710             : 
    5711             : bool
    5712           0 : ArrayType::Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp)
    5713             : {
    5714             :   // This should never happen, but we'll check to be safe.
    5715           0 :   if (!CData::IsCData(obj)) {
    5716           0 :     RootedValue objVal(cx, ObjectValue(*obj));
    5717           0 :     return IncompatibleThisProto(cx, "ArrayType property getter", objVal);
    5718             :   }
    5719             : 
    5720             :   // Bail early if we're not an ArrayType. (This setter is present for all
    5721             :   // CData, regardless of CType.)
    5722           0 :   JSObject* typeObj = CData::GetCType(obj);
    5723           0 :   if (CType::GetTypeCode(typeObj) != TYPE_array)
    5724           0 :     return true;
    5725             : 
    5726             :   // Convert the index to a size_t and bounds-check it.
    5727             :   size_t index;
    5728           0 :   size_t length = GetLength(typeObj);
    5729           0 :   bool ok = jsidToSize(cx, idval, true, &index);
    5730             :   int32_t dummy;
    5731           0 :   if (!ok && JSID_IS_SYMBOL(idval))
    5732           0 :     return true;
    5733             :   bool dummy2;
    5734           0 :   if (!ok && JSID_IS_STRING(idval) &&
    5735           0 :       !StringToInteger(cx, JSID_TO_STRING(idval), &dummy, &dummy2)) {
    5736             :     // String either isn't a number, or doesn't fit in size_t.
    5737             :     // Chances are it's a regular property lookup, so return.
    5738           0 :     return true;
    5739             :   }
    5740           0 :   if (!ok) {
    5741           0 :     return InvalidIndexError(cx, idval);
    5742             :   }
    5743           0 :   if (index >= length) {
    5744           0 :     return InvalidIndexRangeError(cx, index, length);
    5745             :   }
    5746             : 
    5747           0 :   RootedObject baseType(cx, GetBaseType(typeObj));
    5748           0 :   size_t elementSize = CType::GetSize(baseType);
    5749           0 :   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    5750           0 :   return ConvertToJS(cx, baseType, obj, data, false, false, vp);
    5751             : }
    5752             : 
    5753             : bool
    5754           0 : ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
    5755             :                   ObjectOpResult& result)
    5756             : {
    5757             :   // This should never happen, but we'll check to be safe.
    5758           0 :   if (!CData::IsCData(obj)) {
    5759           0 :     RootedValue objVal(cx, ObjectValue(*obj));
    5760           0 :     return IncompatibleThisProto(cx, "ArrayType property setter", objVal);
    5761             :   }
    5762             : 
    5763             :   // Bail early if we're not an ArrayType. (This setter is present for all
    5764             :   // CData, regardless of CType.)
    5765           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    5766           0 :   if (CType::GetTypeCode(typeObj) != TYPE_array)
    5767           0 :     return result.succeed();
    5768             : 
    5769             :   // Convert the index to a size_t and bounds-check it.
    5770             :   size_t index;
    5771           0 :   size_t length = GetLength(typeObj);
    5772           0 :   bool ok = jsidToSize(cx, idval, true, &index);
    5773             :   int32_t dummy;
    5774           0 :   if (!ok && JSID_IS_SYMBOL(idval))
    5775           0 :     return true;
    5776             :   bool dummy2;
    5777           0 :   if (!ok && JSID_IS_STRING(idval) &&
    5778           0 :       !StringToInteger(cx, JSID_TO_STRING(idval), &dummy, &dummy2)) {
    5779             :     // String either isn't a number, or doesn't fit in size_t.
    5780             :     // Chances are it's a regular property lookup, so return.
    5781           0 :     return result.succeed();
    5782             :   }
    5783           0 :   if (!ok) {
    5784           0 :     return InvalidIndexError(cx, idval);
    5785             :   }
    5786           0 :   if (index >= length) {
    5787           0 :     return InvalidIndexRangeError(cx, index, length);
    5788             :   }
    5789             : 
    5790           0 :   RootedObject baseType(cx, GetBaseType(typeObj));
    5791           0 :   size_t elementSize = CType::GetSize(baseType);
    5792           0 :   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    5793           0 :   if (!ImplicitConvert(cx, vp, baseType, data, ConversionType::Setter,
    5794           0 :                        nullptr, nullptr, 0, typeObj, index))
    5795           0 :     return false;
    5796           0 :   return result.succeed();
    5797             : }
    5798             : 
    5799             : bool
    5800           0 : ArrayType::AddressOfElement(JSContext* cx, unsigned argc, Value* vp)
    5801             : {
    5802           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    5803           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    5804           0 :   if (!obj)
    5805           0 :     return false;
    5806           0 :   if (!CData::IsCData(obj)) {
    5807           0 :     return IncompatibleThisProto(cx, "ArrayType.prototype.addressOfElement",
    5808           0 :                                  args.thisv());
    5809             :   }
    5810             : 
    5811           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    5812           0 :   if (CType::GetTypeCode(typeObj) != TYPE_array) {
    5813           0 :     return IncompatibleThisType(cx, "ArrayType.prototype.addressOfElement",
    5814           0 :                                 "non-ArrayType CData", args.thisv());
    5815             :   }
    5816             : 
    5817           0 :   if (args.length() != 1) {
    5818           0 :     return ArgumentLengthError(cx, "ArrayType.prototype.addressOfElement",
    5819           0 :                                "one", "");
    5820             :   }
    5821             : 
    5822           0 :   RootedObject baseType(cx, GetBaseType(typeObj));
    5823           0 :   RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
    5824           0 :   if (!pointerType)
    5825           0 :     return false;
    5826             : 
    5827             :   // Create a PointerType CData object containing null.
    5828           0 :   RootedObject result(cx, CData::Create(cx, pointerType, nullptr, nullptr, true));
    5829           0 :   if (!result)
    5830           0 :     return false;
    5831             : 
    5832           0 :   args.rval().setObject(*result);
    5833             : 
    5834             :   // Convert the index to a size_t and bounds-check it.
    5835             :   size_t index;
    5836           0 :   size_t length = GetLength(typeObj);
    5837           0 :   if (!jsvalToSize(cx, args[0], false, &index)) {
    5838           0 :     return InvalidIndexError(cx, args[0]);
    5839             :   }
    5840           0 :   if (index >= length) {
    5841           0 :     return InvalidIndexRangeError(cx, index, length);
    5842             :   }
    5843             : 
    5844             :   // Manually set the pointer inside the object, so we skip the conversion step.
    5845           0 :   void** data = static_cast<void**>(CData::GetData(result));
    5846           0 :   size_t elementSize = CType::GetSize(baseType);
    5847           0 :   *data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    5848           0 :   return true;
    5849             : }
    5850             : 
    5851             : /*******************************************************************************
    5852             : ** StructType implementation
    5853             : *******************************************************************************/
    5854             : 
    5855             : // For a struct field descriptor 'val' of the form { name : type }, extract
    5856             : // 'name' and 'type'.
    5857             : static JSFlatString*
    5858           0 : ExtractStructField(JSContext* cx, HandleValue val, MutableHandleObject typeObj)
    5859             : {
    5860           0 :   if (val.isPrimitive()) {
    5861           0 :     FieldDescriptorNameTypeError(cx, val);
    5862           0 :     return nullptr;
    5863             :   }
    5864             : 
    5865           0 :   RootedObject obj(cx, &val.toObject());
    5866           0 :   Rooted<IdVector> props(cx, IdVector(cx));
    5867           0 :   if (!JS_Enumerate(cx, obj, &props))
    5868           0 :     return nullptr;
    5869             : 
    5870             :   // make sure we have one, and only one, property
    5871           0 :   if (props.length() != 1) {
    5872           0 :     FieldDescriptorCountError(cx, val, props.length());
    5873           0 :     return nullptr;
    5874             :   }
    5875             : 
    5876           0 :   RootedId nameid(cx, props[0]);
    5877           0 :   if (!JSID_IS_STRING(nameid)) {
    5878           0 :     FieldDescriptorNameError(cx, nameid);
    5879           0 :     return nullptr;
    5880             :   }
    5881             : 
    5882           0 :   RootedValue propVal(cx);
    5883           0 :   if (!JS_GetPropertyById(cx, obj, nameid, &propVal))
    5884           0 :     return nullptr;
    5885             : 
    5886           0 :   if (propVal.isPrimitive() || !CType::IsCType(&propVal.toObject())) {
    5887           0 :     FieldDescriptorTypeError(cx, propVal, nameid);
    5888           0 :     return nullptr;
    5889             :   }
    5890             : 
    5891             :   // Undefined size or zero size struct members are illegal.
    5892             :   // (Zero-size arrays are legal as struct members in C++, but libffi will
    5893             :   // choke on a zero-size struct, so we disallow them.)
    5894           0 :   typeObj.set(&propVal.toObject());
    5895             :   size_t size;
    5896           0 :   if (!CType::GetSafeSize(typeObj, &size) || size == 0) {
    5897           0 :     FieldDescriptorSizeError(cx, typeObj, nameid);
    5898           0 :     return nullptr;
    5899             :   }
    5900             : 
    5901           0 :   return JSID_TO_FLAT_STRING(nameid);
    5902             : }
    5903             : 
    5904             : // For a struct field with 'name' and 'type', add an element of the form
    5905             : // { name : type }.
    5906             : static bool
    5907           0 : AddFieldToArray(JSContext* cx,
    5908             :                 MutableHandleValue element,
    5909             :                 JSFlatString* name_,
    5910             :                 JSObject* typeObj_)
    5911             : {
    5912           0 :   RootedObject typeObj(cx, typeObj_);
    5913           0 :   Rooted<JSFlatString*> name(cx, name_);
    5914           0 :   RootedObject fieldObj(cx, JS_NewPlainObject(cx));
    5915           0 :   if (!fieldObj)
    5916           0 :     return false;
    5917             : 
    5918           0 :   element.setObject(*fieldObj);
    5919             : 
    5920           0 :   AutoStableStringChars nameChars(cx);
    5921           0 :   if (!nameChars.initTwoByte(cx, name))
    5922           0 :       return false;
    5923             : 
    5924           0 :   if (!JS_DefineUCProperty(cx, fieldObj,
    5925           0 :          nameChars.twoByteChars(), name->length(),
    5926             :          typeObj,
    5927             :          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    5928           0 :     return false;
    5929             : 
    5930           0 :   return JS_FreezeObject(cx, fieldObj);
    5931             : }
    5932             : 
    5933             : bool
    5934           4 : StructType::Create(JSContext* cx, unsigned argc, Value* vp)
    5935             : {
    5936           4 :   CallArgs args = CallArgsFromVp(argc, vp);
    5937             : 
    5938             :   // Construct and return a new StructType object.
    5939           4 :   if (args.length() < 1 || args.length() > 2) {
    5940           0 :     return ArgumentLengthError(cx, "StructType", "one or two", "s");
    5941             :   }
    5942             : 
    5943           4 :   Value name = args[0];
    5944           4 :   if (!name.isString()) {
    5945           0 :     return ArgumentTypeMismatch(cx, "first ", "StructType", "a string");
    5946             :   }
    5947             : 
    5948             :   // Get ctypes.StructType.prototype from the ctypes.StructType constructor.
    5949           8 :   RootedObject typeProto(cx, CType::GetProtoFromCtor(&args.callee(), SLOT_STRUCTPROTO));
    5950             : 
    5951             :   // Create a simple StructType with no defined fields. The result will be
    5952             :   // non-instantiable as CData, will have no 'prototype' property, and will
    5953             :   // have undefined size and alignment and no ffi_type.
    5954           8 :   RootedObject result(cx, CType::Create(cx, typeProto, nullptr, TYPE_struct,
    5955             :                                         name.toString(),
    5956             :                                         JS::UndefinedHandleValue,
    5957           8 :                                         JS::UndefinedHandleValue, nullptr));
    5958           4 :   if (!result)
    5959           0 :     return false;
    5960             : 
    5961           4 :   if (args.length() == 2) {
    5962           0 :     RootedObject arr(cx, args[1].isObject() ? &args[1].toObject() : nullptr);
    5963             :     bool isArray;
    5964           0 :     if (!arr) {
    5965           0 :         isArray = false;
    5966             :     } else {
    5967           0 :         if (!JS_IsArrayObject(cx, arr, &isArray))
    5968           0 :            return false;
    5969             :     }
    5970           0 :     if (!isArray)
    5971           0 :       return ArgumentTypeMismatch(cx, "second ", "StructType", "an array");
    5972             : 
    5973             :     // Define the struct fields.
    5974           0 :     if (!DefineInternal(cx, result, arr))
    5975           0 :       return false;
    5976             :   }
    5977             : 
    5978           4 :   args.rval().setObject(*result);
    5979           4 :   return true;
    5980             : }
    5981             : 
    5982             : bool
    5983           0 : StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsObj_)
    5984             : {
    5985           0 :   RootedObject typeObj(cx, typeObj_);
    5986           0 :   RootedObject fieldsObj(cx, fieldsObj_);
    5987             : 
    5988             :   uint32_t len;
    5989           0 :   ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len));
    5990             : 
    5991             :   // Get the common prototype for CData objects of this type from
    5992             :   // ctypes.CType.prototype.
    5993           0 :   RootedObject dataProto(cx, CType::GetProtoFromType(cx, typeObj, SLOT_STRUCTDATAPROTO));
    5994           0 :   if (!dataProto)
    5995           0 :     return false;
    5996             : 
    5997             :   // Set up the 'prototype' and 'prototype.constructor' properties.
    5998             :   // The prototype will reflect the struct fields as properties on CData objects
    5999             :   // created from this type.
    6000           0 :   RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto));
    6001           0 :   if (!prototype)
    6002           0 :     return false;
    6003             : 
    6004           0 :   if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
    6005             :                          JSPROP_READONLY | JSPROP_PERMANENT))
    6006           0 :     return false;
    6007             : 
    6008             :   // Create a FieldInfoHash to stash on the type object.
    6009           0 :   Rooted<FieldInfoHash> fields(cx);
    6010           0 :   if (!fields.init(len)) {
    6011           0 :     JS_ReportOutOfMemory(cx);
    6012           0 :     return false;
    6013             :   }
    6014             : 
    6015             :   // Process the field types.
    6016             :   size_t structSize, structAlign;
    6017           0 :   if (len != 0) {
    6018           0 :     structSize = 0;
    6019           0 :     structAlign = 0;
    6020             : 
    6021           0 :     for (uint32_t i = 0; i < len; ++i) {
    6022           0 :       RootedValue item(cx);
    6023           0 :       if (!JS_GetElement(cx, fieldsObj, i, &item))
    6024           0 :         return false;
    6025             : 
    6026           0 :       RootedObject fieldType(cx, nullptr);
    6027           0 :       Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, &fieldType));
    6028           0 :       if (!name)
    6029           0 :         return false;
    6030             : 
    6031             :       // Make sure each field name is unique
    6032           0 :       FieldInfoHash::AddPtr entryPtr = fields.lookupForAdd(name);
    6033           0 :       if (entryPtr) {
    6034           0 :         return DuplicateFieldError(cx, name);
    6035             :       }
    6036             : 
    6037             :       // Add the field to the StructType's 'prototype' property.
    6038           0 :       AutoStableStringChars nameChars(cx);
    6039           0 :       if (!nameChars.initTwoByte(cx, name))
    6040           0 :         return false;
    6041             : 
    6042           0 :       RootedFunction getter(cx, NewFunctionWithReserved(cx, StructType::FieldGetter, 0, 0, nullptr));
    6043           0 :       if (!getter)
    6044           0 :         return false;
    6045           0 :       SetFunctionNativeReserved(getter, StructType::SLOT_FIELDNAME,
    6046           0 :                                 StringValue(JS_FORGET_STRING_FLATNESS(name)));
    6047           0 :       RootedObject getterObj(cx, JS_GetFunctionObject(getter));
    6048             : 
    6049           0 :       RootedFunction setter(cx, NewFunctionWithReserved(cx, StructType::FieldSetter, 1, 0, nullptr));
    6050           0 :       if (!setter)
    6051           0 :         return false;
    6052           0 :       SetFunctionNativeReserved(setter, StructType::SLOT_FIELDNAME,
    6053           0 :                                 StringValue(JS_FORGET_STRING_FLATNESS(name)));
    6054           0 :       RootedObject setterObj(cx, JS_GetFunctionObject(setter));
    6055             : 
    6056           0 :       if (!JS_DefineUCProperty(cx, prototype,
    6057           0 :              nameChars.twoByteChars(), name->length(), UndefinedHandleValue,
    6058             :              JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER,
    6059           0 :              JS_DATA_TO_FUNC_PTR(JSNative, getterObj.get()),
    6060           0 :              JS_DATA_TO_FUNC_PTR(JSNative, setterObj.get())))
    6061             :       {
    6062           0 :         return false;
    6063             :       }
    6064             : 
    6065           0 :       size_t fieldSize = CType::GetSize(fieldType);
    6066           0 :       size_t fieldAlign = CType::GetAlignment(fieldType);
    6067           0 :       size_t fieldOffset = Align(structSize, fieldAlign);
    6068             :       // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
    6069             :       // be zero, we can safely check fieldOffset + fieldSize without first
    6070             :       // checking fieldOffset for overflow.
    6071           0 :       if (fieldOffset + fieldSize < structSize) {
    6072           0 :         SizeOverflow(cx, "struct size", "size_t");
    6073           0 :         return false;
    6074             :       }
    6075             : 
    6076             :       // Add field name to the hash
    6077           0 :       FieldInfo info;
    6078           0 :       info.mType = fieldType;
    6079           0 :       info.mIndex = i;
    6080           0 :       info.mOffset = fieldOffset;
    6081           0 :       if (!fields.add(entryPtr, name, info)) {
    6082           0 :         JS_ReportOutOfMemory(cx);
    6083           0 :         return false;
    6084             :       }
    6085             : 
    6086           0 :       structSize = fieldOffset + fieldSize;
    6087             : 
    6088           0 :       if (fieldAlign > structAlign)
    6089           0 :         structAlign = fieldAlign;
    6090             :     }
    6091             : 
    6092             :     // Pad the struct tail according to struct alignment.
    6093           0 :     size_t structTail = Align(structSize, structAlign);
    6094           0 :     if (structTail < structSize) {
    6095           0 :       SizeOverflow(cx, "struct size", "size_t");
    6096           0 :       return false;
    6097             :     }
    6098           0 :     structSize = structTail;
    6099             : 
    6100             :   } else {
    6101             :     // Empty structs are illegal in C, but are legal and have a size of
    6102             :     // 1 byte in C++. We're going to allow them, and trick libffi into
    6103             :     // believing this by adding a char member. The resulting struct will have
    6104             :     // no getters or setters, and will be initialized to zero.
    6105           0 :     structSize = 1;
    6106           0 :     structAlign = 1;
    6107             :   }
    6108             : 
    6109           0 :   RootedValue sizeVal(cx);
    6110           0 :   if (!SizeTojsval(cx, structSize, &sizeVal)) {
    6111           0 :     SizeOverflow(cx, "struct size", "double");
    6112           0 :     return false;
    6113             :   }
    6114             : 
    6115             :   // Move the field hash to the heap and store it in the typeObj.
    6116           0 :   FieldInfoHash *heapHash = cx->new_<FieldInfoHash>(mozilla::Move(fields.get()));
    6117           0 :   if (!heapHash) {
    6118           0 :     JS_ReportOutOfMemory(cx);
    6119           0 :     return false;
    6120             :   }
    6121           0 :   MOZ_ASSERT(heapHash->initialized());
    6122           0 :   JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PrivateValue(heapHash));
    6123             : 
    6124           0 :   JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
    6125           0 :   JS_SetReservedSlot(typeObj, SLOT_ALIGN, Int32Value(structAlign));
    6126             :   //if (!JS_FreezeObject(cx, prototype)0 // XXX fixme - see bug 541212!
    6127             :   //  return false;
    6128           0 :   JS_SetReservedSlot(typeObj, SLOT_PROTO, ObjectValue(*prototype));
    6129           0 :   return true;
    6130             : }
    6131             : 
    6132             : UniquePtrFFIType
    6133           0 : StructType::BuildFFIType(JSContext* cx, JSObject* obj)
    6134             : {
    6135           0 :   MOZ_ASSERT(CType::IsCType(obj));
    6136           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    6137           0 :   MOZ_ASSERT(CType::IsSizeDefined(obj));
    6138             : 
    6139           0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    6140           0 :   size_t len = fields->count();
    6141             : 
    6142           0 :   size_t structSize = CType::GetSize(obj);
    6143           0 :   size_t structAlign = CType::GetAlignment(obj);
    6144             : 
    6145           0 :   auto ffiType = cx->make_unique<ffi_type>();
    6146           0 :   if (!ffiType) {
    6147           0 :     JS_ReportOutOfMemory(cx);
    6148           0 :     return nullptr;
    6149             :   }
    6150           0 :   ffiType->type = FFI_TYPE_STRUCT;
    6151             : 
    6152           0 :   size_t count = len != 0 ? len + 1 : 2;
    6153           0 :   auto elements = cx->make_pod_array<ffi_type*>(count);
    6154           0 :   if (!elements) {
    6155           0 :     JS_ReportOutOfMemory(cx);
    6156           0 :     return nullptr;
    6157             :   }
    6158             : 
    6159           0 :   if (len != 0) {
    6160           0 :     elements[len] = nullptr;
    6161             : 
    6162           0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    6163           0 :       const FieldInfoHash::Entry& entry = r.front();
    6164           0 :       ffi_type* fieldType = CType::GetFFIType(cx, entry.value().mType);
    6165           0 :       if (!fieldType)
    6166           0 :         return nullptr;
    6167           0 :       elements[entry.value().mIndex] = fieldType;
    6168             :     }
    6169             :   } else {
    6170             :     // Represent an empty struct as having a size of 1 byte, just like C++.
    6171           0 :     MOZ_ASSERT(structSize == 1);
    6172           0 :     MOZ_ASSERT(structAlign == 1);
    6173           0 :     elements[0] = &ffi_type_uint8;
    6174           0 :     elements[1] = nullptr;
    6175             :   }
    6176             : 
    6177           0 :   ffiType->elements = elements.release();
    6178             : 
    6179             : #ifdef DEBUG
    6180             :   // Perform a sanity check: the result of our struct size and alignment
    6181             :   // calculations should match libffi's. We force it to do this calculation
    6182             :   // by calling ffi_prep_cif.
    6183             :   ffi_cif cif;
    6184           0 :   ffiType->size = 0;
    6185           0 :   ffiType->alignment = 0;
    6186           0 :   ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), nullptr);
    6187           0 :   MOZ_ASSERT(status == FFI_OK);
    6188           0 :   MOZ_ASSERT(structSize == ffiType->size);
    6189           0 :   MOZ_ASSERT(structAlign == ffiType->alignment);
    6190             : #else
    6191             :   // Fill in the ffi_type's size and align fields. This makes libffi treat the
    6192             :   // type as initialized; it will not recompute the values. (We assume
    6193             :   // everything agrees; if it doesn't, we really want to know about it, which
    6194             :   // is the purpose of the above debug-only check.)
    6195             :   ffiType->size = structSize;
    6196             :   ffiType->alignment = structAlign;
    6197             : #endif
    6198             : 
    6199           0 :   return Move(ffiType);
    6200             : }
    6201             : 
    6202             : bool
    6203           0 : StructType::Define(JSContext* cx, unsigned argc, Value* vp)
    6204             : {
    6205           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    6206           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    6207           0 :   if (!obj)
    6208           0 :     return false;
    6209           0 :   if (!CType::IsCType(obj)) {
    6210           0 :     return IncompatibleThisProto(cx, "StructType.prototype.define",
    6211           0 :                                  args.thisv());
    6212             :   }
    6213           0 :   if (CType::GetTypeCode(obj) != TYPE_struct) {
    6214           0 :     return IncompatibleThisType(cx, "StructType.prototype.define",
    6215           0 :                                 "non-StructType", args.thisv());
    6216             :   }
    6217             : 
    6218           0 :   if (CType::IsSizeDefined(obj)) {
    6219           0 :     JS_ReportErrorASCII(cx, "StructType has already been defined");
    6220           0 :     return false;
    6221             :   }
    6222             : 
    6223           0 :   if (args.length() != 1) {
    6224           0 :     return ArgumentLengthError(cx, "StructType.prototype.define", "one", "");
    6225             :   }
    6226             : 
    6227           0 :   HandleValue arg = args[0];
    6228           0 :   if (arg.isPrimitive()) {
    6229           0 :     return ArgumentTypeMismatch(cx, "", "StructType.prototype.define",
    6230           0 :                                 "an array");
    6231             :   }
    6232             : 
    6233             :   bool isArray;
    6234           0 :   if (!arg.isObject()) {
    6235           0 :     isArray = false;
    6236             :   } else {
    6237           0 :     if (!JS_IsArrayObject(cx, arg, &isArray))
    6238           0 :       return false;
    6239             :   }
    6240             : 
    6241           0 :   if (!isArray) {
    6242           0 :     return ArgumentTypeMismatch(cx, "", "StructType.prototype.define",
    6243           0 :                                 "an array");
    6244             :   }
    6245             : 
    6246           0 :   RootedObject arr(cx, &arg.toObject());
    6247           0 :   return DefineInternal(cx, obj, arr);
    6248             : }
    6249             : 
    6250             : bool
    6251           0 : StructType::ConstructData(JSContext* cx,
    6252             :                           HandleObject obj,
    6253             :                           const CallArgs& args)
    6254             : {
    6255           0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_struct) {
    6256           0 :     return IncompatibleCallee(cx, "StructType constructor", obj);
    6257             :   }
    6258             : 
    6259           0 :   if (!CType::IsSizeDefined(obj)) {
    6260           0 :     JS_ReportErrorASCII(cx, "cannot construct an opaque StructType");
    6261           0 :     return false;
    6262             :   }
    6263             : 
    6264           0 :   JSObject* result = CData::Create(cx, obj, nullptr, nullptr, true);
    6265           0 :   if (!result)
    6266           0 :     return false;
    6267             : 
    6268           0 :   args.rval().setObject(*result);
    6269             : 
    6270           0 :   if (args.length() == 0)
    6271           0 :     return true;
    6272             : 
    6273           0 :   char* buffer = static_cast<char*>(CData::GetData(result));
    6274           0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    6275             : 
    6276           0 :   if (args.length() == 1) {
    6277             :     // There are two possible interpretations of the argument:
    6278             :     // 1) It may be an object '{ ... }' with properties representing the
    6279             :     //    struct fields intended to ExplicitConvert wholesale to our StructType.
    6280             :     // 2) If the struct contains one field, the arg may be intended to
    6281             :     //    ImplicitConvert directly to that arg's CType.
    6282             :     // Thankfully, the conditions for these two possibilities to succeed
    6283             :     // are mutually exclusive, so we can pick the right one.
    6284             : 
    6285             :     // Try option 1) first.
    6286           0 :     if (ExplicitConvert(cx, args[0], obj, buffer, ConversionType::Construct))
    6287           0 :       return true;
    6288             : 
    6289           0 :     if (fields->count() != 1)
    6290           0 :       return false;
    6291             : 
    6292             :     // If ExplicitConvert failed, and there is no pending exception, then assume
    6293             :     // hard failure (out of memory, or some other similarly serious condition).
    6294           0 :     if (!JS_IsExceptionPending(cx))
    6295           0 :       return false;
    6296             : 
    6297             :     // Otherwise, assume soft failure, and clear the pending exception so that we
    6298             :     // can throw a different one as required.
    6299           0 :     JS_ClearPendingException(cx);
    6300             : 
    6301             :     // Fall through to try option 2).
    6302             :   }
    6303             : 
    6304             :   // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'.
    6305             :   // ImplicitConvert each field.
    6306           0 :   if (args.length() == fields->count()) {
    6307           0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    6308           0 :       const FieldInfo& field = r.front().value();
    6309           0 :       MOZ_ASSERT(field.mIndex < fields->count());  /* Quantified invariant */
    6310           0 :       if (!ImplicitConvert(cx, args[field.mIndex], field.mType,
    6311           0 :                            buffer + field.mOffset, ConversionType::Construct,
    6312           0 :                            nullptr, nullptr, 0, obj, field.mIndex))
    6313           0 :         return false;
    6314             :     }
    6315             : 
    6316           0 :     return true;
    6317             :   }
    6318             : 
    6319           0 :   size_t count = fields->count();
    6320           0 :   if (count >= 2) {
    6321             :     char fieldLengthStr[32];
    6322           0 :     SprintfLiteral(fieldLengthStr, "0, 1, or %" PRIuSIZE, count);
    6323             :     return ArgumentLengthError(cx, "StructType constructor", fieldLengthStr,
    6324           0 :                                "s");
    6325             :   }
    6326           0 :   return ArgumentLengthError(cx, "StructType constructor", "at most one", "");
    6327             : }
    6328             : 
    6329             : const FieldInfoHash*
    6330           0 : StructType::GetFieldInfo(JSObject* obj)
    6331             : {
    6332           0 :   MOZ_ASSERT(CType::IsCType(obj));
    6333           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    6334             : 
    6335           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
    6336           0 :   MOZ_ASSERT(!slot.isUndefined() && slot.toPrivate());
    6337             : 
    6338           0 :   return static_cast<const FieldInfoHash*>(slot.toPrivate());
    6339             : }
    6340             : 
    6341             : const FieldInfo*
    6342           0 : StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString* name)
    6343             : {
    6344           0 :   MOZ_ASSERT(CType::IsCType(obj));
    6345           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    6346             : 
    6347           0 :   FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name);
    6348           0 :   if (ptr)
    6349           0 :     return &ptr->value();
    6350             : 
    6351           0 :   FieldMissingError(cx, obj, name);
    6352           0 :   return nullptr;
    6353             : }
    6354             : 
    6355             : JSObject*
    6356           0 : StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
    6357             : {
    6358           0 :   MOZ_ASSERT(CType::IsCType(obj));
    6359           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    6360           0 :   MOZ_ASSERT(CType::IsSizeDefined(obj));
    6361             : 
    6362           0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    6363           0 :   size_t len = fields->count();
    6364             : 
    6365             :   // Prepare a new array for the 'fields' property of the StructType.
    6366           0 :   JS::AutoValueVector fieldsVec(cx);
    6367           0 :   if (!fieldsVec.resize(len))
    6368           0 :     return nullptr;
    6369             : 
    6370           0 :   for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    6371           0 :     const FieldInfoHash::Entry& entry = r.front();
    6372             :     // Add the field descriptor to the array.
    6373           0 :     if (!AddFieldToArray(cx, fieldsVec[entry.value().mIndex],
    6374           0 :                          entry.key(), entry.value().mType))
    6375           0 :       return nullptr;
    6376             :   }
    6377             : 
    6378           0 :   RootedObject fieldsProp(cx, JS_NewArrayObject(cx, fieldsVec));
    6379           0 :   if (!fieldsProp)
    6380           0 :     return nullptr;
    6381             : 
    6382             :   // Seal the fields array.
    6383           0 :   if (!JS_FreezeObject(cx, fieldsProp))
    6384           0 :     return nullptr;
    6385             : 
    6386           0 :   return fieldsProp;
    6387             : }
    6388             : 
    6389             : /* static */ bool
    6390           0 : StructType::IsStruct(HandleValue v)
    6391             : {
    6392           0 :   if (!v.isObject())
    6393           0 :     return false;
    6394           0 :   JSObject* obj = &v.toObject();
    6395           0 :   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_struct;
    6396             : }
    6397             : 
    6398             : bool
    6399           0 : StructType::FieldsArrayGetter(JSContext* cx, const JS::CallArgs& args)
    6400             : {
    6401           0 :   RootedObject obj(cx, &args.thisv().toObject());
    6402             : 
    6403           0 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_FIELDS));
    6404             : 
    6405           0 :   if (!CType::IsSizeDefined(obj)) {
    6406           0 :     MOZ_ASSERT(args.rval().isUndefined());
    6407           0 :     return true;
    6408             :   }
    6409             : 
    6410           0 :   if (args.rval().isUndefined()) {
    6411             :     // Build the 'fields' array lazily.
    6412           0 :     JSObject* fields = BuildFieldsArray(cx, obj);
    6413           0 :     if (!fields)
    6414           0 :       return false;
    6415           0 :     JS_SetReservedSlot(obj, SLOT_FIELDS, ObjectValue(*fields));
    6416             : 
    6417           0 :     args.rval().setObject(*fields);
    6418             :   }
    6419             : 
    6420           0 :   MOZ_ASSERT(args.rval().isObject());
    6421           0 :   return true;
    6422             : }
    6423             : 
    6424             : bool
    6425           0 : StructType::FieldGetter(JSContext* cx, unsigned argc, Value* vp)
    6426             : {
    6427           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    6428             : 
    6429           0 :   if (!args.thisv().isObject()) {
    6430           0 :     return IncompatibleThisProto(cx, "StructType property getter", args.thisv());
    6431             :   }
    6432             : 
    6433           0 :   RootedObject obj(cx, &args.thisv().toObject());
    6434           0 :   if (!CData::IsCData(obj)) {
    6435           0 :     return IncompatibleThisProto(cx, "StructType property getter", args.thisv());
    6436             :   }
    6437             : 
    6438           0 :   JSObject* typeObj = CData::GetCType(obj);
    6439           0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    6440           0 :     return IncompatibleThisType(cx, "StructType property getter",
    6441           0 :                                 "non-StructType CData", args.thisv());
    6442             :   }
    6443             : 
    6444           0 :   RootedValue nameVal(cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME));
    6445           0 :   Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString()));
    6446           0 :   if (!name)
    6447           0 :     return false;
    6448             : 
    6449           0 :   const FieldInfo* field = LookupField(cx, typeObj, name);
    6450           0 :   if (!field)
    6451           0 :     return false;
    6452             : 
    6453           0 :   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    6454           0 :   RootedObject fieldType(cx, field->mType);
    6455           0 :   return ConvertToJS(cx, fieldType, obj, data, false, false, args.rval());
    6456             : }
    6457             : 
    6458             : bool
    6459           0 : StructType::FieldSetter(JSContext* cx, unsigned argc, Value* vp)
    6460             : {
    6461           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    6462             : 
    6463           0 :   if (!args.thisv().isObject()) {
    6464           0 :     return IncompatibleThisProto(cx, "StructType property setter", args.thisv());
    6465             :   }
    6466             : 
    6467           0 :   RootedObject obj(cx, &args.thisv().toObject());
    6468           0 :   if (!CData::IsCData(obj)) {
    6469           0 :     return IncompatibleThisProto(cx, "StructType property setter", args.thisv());
    6470             :   }
    6471             : 
    6472           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    6473           0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    6474           0 :     return IncompatibleThisType(cx, "StructType property setter",
    6475           0 :                                 "non-StructType CData", args.thisv());
    6476             :   }
    6477             : 
    6478           0 :   RootedValue nameVal(cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME));
    6479           0 :   Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString()));
    6480           0 :   if (!name)
    6481           0 :     return false;
    6482             : 
    6483           0 :   const FieldInfo* field = LookupField(cx, typeObj, name);
    6484           0 :   if (!field)
    6485           0 :     return false;
    6486             : 
    6487           0 :   args.rval().setUndefined();
    6488             : 
    6489           0 :   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    6490           0 :   return ImplicitConvert(cx, args.get(0), field->mType, data, ConversionType::Setter, nullptr,
    6491           0 :                          nullptr, 0, typeObj, field->mIndex);
    6492             : }
    6493             : 
    6494             : bool
    6495           0 : StructType::AddressOfField(JSContext* cx, unsigned argc, Value* vp)
    6496             : {
    6497           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    6498           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    6499           0 :   if (!obj)
    6500           0 :     return false;
    6501           0 :  if (!CData::IsCData(obj)) {
    6502           0 :     return IncompatibleThisProto(cx, "StructType.prototype.addressOfField",
    6503           0 :                                  args.thisv());
    6504             :   }
    6505             : 
    6506           0 :   JSObject* typeObj = CData::GetCType(obj);
    6507           0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    6508           0 :     return IncompatibleThisType(cx, "StructType.prototype.addressOfField",
    6509           0 :                                 "non-StructType CData", args.thisv());
    6510             :   }
    6511             : 
    6512           0 :   if (args.length() != 1) {
    6513           0 :     return ArgumentLengthError(cx, "StructType.prototype.addressOfField",
    6514           0 :                                "one", "");
    6515             :   }
    6516             : 
    6517           0 :   if (!args[0].isString()) {
    6518           0 :     return ArgumentTypeMismatch(cx, "", "StructType.prototype.addressOfField",
    6519           0 :                                 "a string");
    6520             :   }
    6521             : 
    6522           0 :   JSFlatString* str = JS_FlattenString(cx, args[0].toString());
    6523           0 :   if (!str)
    6524           0 :     return false;
    6525             : 
    6526           0 :   const FieldInfo* field = LookupField(cx, typeObj, str);
    6527           0 :   if (!field)
    6528           0 :     return false;
    6529             : 
    6530           0 :   RootedObject baseType(cx, field->mType);
    6531           0 :   RootedObject pointerType(cx, PointerType::CreateInternal(cx, baseType));
    6532           0 :   if (!pointerType)
    6533           0 :     return false;
    6534             : 
    6535             :   // Create a PointerType CData object containing null.
    6536           0 :   JSObject* result = CData::Create(cx, pointerType, nullptr, nullptr, true);
    6537           0 :   if (!result)
    6538           0 :     return false;
    6539             : 
    6540           0 :   args.rval().setObject(*result);
    6541             : 
    6542             :   // Manually set the pointer inside the object, so we skip the conversion step.
    6543           0 :   void** data = static_cast<void**>(CData::GetData(result));
    6544           0 :   *data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    6545           0 :   return true;
    6546             : }
    6547             : 
    6548             : /*******************************************************************************
    6549             : ** FunctionType implementation
    6550             : *******************************************************************************/
    6551             : 
    6552             : // Helper class for handling allocation of function arguments.
    6553             : struct AutoValue
    6554             : {
    6555           0 :   AutoValue() : mData(nullptr) { }
    6556             : 
    6557           0 :   ~AutoValue()
    6558           0 :   {
    6559           0 :     js_free(mData);
    6560           0 :   }
    6561             : 
    6562           0 :   bool SizeToType(JSContext* cx, JSObject* type)
    6563             :   {
    6564             :     // Allocate a minimum of sizeof(ffi_arg) to handle small integers.
    6565           0 :     size_t size = Align(CType::GetSize(type), sizeof(ffi_arg));
    6566           0 :     mData = js_malloc(size);
    6567           0 :     if (mData)
    6568           0 :       memset(mData, 0, size);
    6569           0 :     return mData != nullptr;
    6570             :   }
    6571             : 
    6572             :   void* mData;
    6573             : };
    6574             : 
    6575             : static bool
    6576           0 : GetABI(JSContext* cx, HandleValue abiType, ffi_abi* result)
    6577             : {
    6578           0 :   if (abiType.isPrimitive())
    6579           0 :     return false;
    6580             : 
    6581           0 :   ABICode abi = GetABICode(abiType.toObjectOrNull());
    6582             : 
    6583             :   // determine the ABI from the subset of those available on the
    6584             :   // given platform. ABI_DEFAULT specifies the default
    6585             :   // C calling convention (cdecl) on each platform.
    6586           0 :   switch (abi) {
    6587             :   case ABI_DEFAULT:
    6588           0 :     *result = FFI_DEFAULT_ABI;
    6589           0 :     return true;
    6590             :   case ABI_THISCALL:
    6591             : #if defined(_WIN64)
    6592             :     *result = FFI_WIN64;
    6593             :     return true;
    6594             : #elif defined(_WIN32)
    6595             :     *result = FFI_THISCALL;
    6596             :     return true;
    6597             : #else
    6598           0 :     break;
    6599             : #endif
    6600             :   case ABI_STDCALL:
    6601             :   case ABI_WINAPI:
    6602             : #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
    6603             :     *result = FFI_STDCALL;
    6604             :     return true;
    6605             : #elif (defined(_WIN64))
    6606             :     // We'd like the same code to work across Win32 and Win64, so stdcall_api
    6607             :     // and winapi_abi become aliases to the lone Win64 ABI.
    6608             :     *result = FFI_WIN64;
    6609             :     return true;
    6610             : #endif
    6611             :   case INVALID_ABI:
    6612           0 :     break;
    6613             :   }
    6614           0 :   return false;
    6615             : }
    6616             : 
    6617             : static JSObject*
    6618           0 : PrepareType(JSContext* cx, uint32_t index, HandleValue type)
    6619             : {
    6620           0 :   if (type.isPrimitive() || !CType::IsCType(type.toObjectOrNull())) {
    6621           0 :     FunctionArgumentTypeError(cx, index, type, "is not a ctypes type");
    6622           0 :     return nullptr;
    6623             :   }
    6624             : 
    6625           0 :   JSObject* result = type.toObjectOrNull();
    6626           0 :   TypeCode typeCode = CType::GetTypeCode(result);
    6627             : 
    6628           0 :   if (typeCode == TYPE_array) {
    6629             :     // convert array argument types to pointers, just like C.
    6630             :     // ImplicitConvert will do the same, when passing an array as data.
    6631           0 :     RootedObject baseType(cx, ArrayType::GetBaseType(result));
    6632           0 :     result = PointerType::CreateInternal(cx, baseType);
    6633           0 :     if (!result)
    6634           0 :       return nullptr;
    6635             : 
    6636           0 :   } else if (typeCode == TYPE_void_t || typeCode == TYPE_function) {
    6637             :     // disallow void or function argument types
    6638           0 :     FunctionArgumentTypeError(cx, index, type, "cannot be void or function");
    6639           0 :     return nullptr;
    6640             :   }
    6641             : 
    6642           0 :   if (!CType::IsSizeDefined(result)) {
    6643           0 :     FunctionArgumentTypeError(cx, index, type, "must have defined size");
    6644           0 :     return nullptr;
    6645             :   }
    6646             : 
    6647             :   // libffi cannot pass types of zero size by value.
    6648           0 :   MOZ_ASSERT(CType::GetSize(result) != 0);
    6649             : 
    6650           0 :   return result;
    6651             : }
    6652             : 
    6653             : static JSObject*
    6654           0 : PrepareReturnType(JSContext* cx, HandleValue type)
    6655             : {
    6656           0 :   if (type.isPrimitive() || !CType::IsCType(type.toObjectOrNull())) {
    6657           0 :     FunctionReturnTypeError(cx, type, "is not a ctypes type");
    6658           0 :     return nullptr;
    6659             :   }
    6660             : 
    6661           0 :   JSObject* result = type.toObjectOrNull();
    6662           0 :   TypeCode typeCode = CType::GetTypeCode(result);
    6663             : 
    6664             :   // Arrays and functions can never be return types.
    6665           0 :   if (typeCode == TYPE_array || typeCode == TYPE_function) {
    6666           0 :     FunctionReturnTypeError(cx, type, "cannot be an array or function");
    6667           0 :     return nullptr;
    6668             :   }
    6669             : 
    6670           0 :   if (typeCode != TYPE_void_t && !CType::IsSizeDefined(result)) {
    6671           0 :     FunctionReturnTypeError(cx, type, "must have defined size");
    6672           0 :     return nullptr;
    6673             :   }
    6674             : 
    6675             :   // libffi cannot pass types of zero size by value.
    6676           0 :   MOZ_ASSERT(typeCode == TYPE_void_t || CType::GetSize(result) != 0);
    6677             : 
    6678           0 :   return result;
    6679             : }
    6680             : 
    6681             : static MOZ_ALWAYS_INLINE bool
    6682           0 : IsEllipsis(JSContext* cx, HandleValue v, bool* isEllipsis)
    6683             : {
    6684           0 :   *isEllipsis = false;
    6685           0 :   if (!v.isString())
    6686           0 :     return true;
    6687           0 :   JSString* str = v.toString();
    6688           0 :   if (str->length() != 3)
    6689           0 :     return true;
    6690           0 :   JSLinearString* linear = str->ensureLinear(cx);
    6691           0 :   if (!linear)
    6692           0 :     return false;
    6693           0 :   char16_t dot = '.';
    6694           0 :   *isEllipsis = (linear->latin1OrTwoByteChar(0) == dot &&
    6695           0 :                  linear->latin1OrTwoByteChar(1) == dot &&
    6696           0 :                  linear->latin1OrTwoByteChar(2) == dot);
    6697           0 :   return true;
    6698             : }
    6699             : 
    6700             : static bool
    6701           0 : PrepareCIF(JSContext* cx,
    6702             :            FunctionInfo* fninfo)
    6703             : {
    6704             :   ffi_abi abi;
    6705           0 :   RootedValue abiType(cx, ObjectOrNullValue(fninfo->mABI));
    6706           0 :   if (!GetABI(cx, abiType, &abi)) {
    6707           0 :     JS_ReportErrorASCII(cx, "Invalid ABI specification");
    6708           0 :     return false;
    6709             :   }
    6710             : 
    6711           0 :   ffi_type* rtype = CType::GetFFIType(cx, fninfo->mReturnType);
    6712           0 :   if (!rtype)
    6713           0 :     return false;
    6714             : 
    6715             :   ffi_status status =
    6716           0 :     ffi_prep_cif(&fninfo->mCIF,
    6717             :                  abi,
    6718           0 :                  fninfo->mFFITypes.length(),
    6719             :                  rtype,
    6720           0 :                  fninfo->mFFITypes.begin());
    6721             : 
    6722           0 :   switch (status) {
    6723             :   case FFI_OK:
    6724           0 :     return true;
    6725             :   case FFI_BAD_ABI:
    6726           0 :     JS_ReportErrorASCII(cx, "Invalid ABI specification");
    6727           0 :     return false;
    6728             :   case FFI_BAD_TYPEDEF:
    6729           0 :     JS_ReportErrorASCII(cx, "Invalid type specification");
    6730           0 :     return false;
    6731             :   default:
    6732           0 :     JS_ReportErrorASCII(cx, "Unknown libffi error");
    6733           0 :     return false;
    6734             :   }
    6735             : }
    6736             : 
    6737             : void
    6738           0 : FunctionType::BuildSymbolName(JSString* name,
    6739             :                               JSObject* typeObj,
    6740             :                               AutoCString& result)
    6741             : {
    6742           0 :   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
    6743             : 
    6744           0 :   switch (GetABICode(fninfo->mABI)) {
    6745             :   case ABI_DEFAULT:
    6746             :   case ABI_THISCALL:
    6747             :   case ABI_WINAPI:
    6748             :     // For cdecl or WINAPI functions, no mangling is necessary.
    6749           0 :     AppendString(result, name);
    6750           0 :     break;
    6751             : 
    6752             :   case ABI_STDCALL: {
    6753             : #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
    6754             :     // On WIN32, stdcall functions look like:
    6755             :     //   _foo@40
    6756             :     // where 'foo' is the function name, and '40' is the aligned size of the
    6757             :     // arguments.
    6758             :     AppendString(result, "_");
    6759             :     AppendString(result, name);
    6760             :     AppendString(result, "@");
    6761             : 
    6762             :     // Compute the suffix by aligning each argument to sizeof(ffi_arg).
    6763             :     size_t size = 0;
    6764             :     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    6765             :       JSObject* argType = fninfo->mArgTypes[i];
    6766             :       size += Align(CType::GetSize(argType), sizeof(ffi_arg));
    6767             :     }
    6768             : 
    6769             :     IntegerToString(size, 10, result);
    6770             : #elif defined(_WIN64)
    6771             :     // On Win64, stdcall is an alias to the default ABI for compatibility, so no
    6772             :     // mangling is done.
    6773             :     AppendString(result, name);
    6774             : #endif
    6775           0 :     break;
    6776             :   }
    6777             : 
    6778             :   case INVALID_ABI:
    6779           0 :     MOZ_CRASH("invalid abi");
    6780             :   }
    6781           0 : }
    6782             : 
    6783             : static bool
    6784           0 : CreateFunctionInfo(JSContext* cx,
    6785             :                    HandleObject typeObj,
    6786             :                    HandleValue abiType,
    6787             :                    HandleObject returnType,
    6788             :                    const HandleValueArray& args)
    6789             : {
    6790           0 :   FunctionInfo* fninfo(cx->new_<FunctionInfo>());
    6791           0 :   if (!fninfo) {
    6792           0 :     JS_ReportOutOfMemory(cx);
    6793           0 :     return false;
    6794             :   }
    6795             : 
    6796             :   // Stash the FunctionInfo in a reserved slot.
    6797           0 :   JS_SetReservedSlot(typeObj, SLOT_FNINFO, PrivateValue(fninfo));
    6798             : 
    6799             :   ffi_abi abi;
    6800           0 :   if (!GetABI(cx, abiType, &abi)) {
    6801           0 :     JS_ReportErrorASCII(cx, "Invalid ABI specification");
    6802           0 :     return false;
    6803             :   }
    6804           0 :   fninfo->mABI = abiType.toObjectOrNull();
    6805             : 
    6806           0 :   fninfo->mReturnType = returnType;
    6807             : 
    6808             :   // prepare the argument types
    6809           0 :   if (!fninfo->mArgTypes.reserve(args.length()) ||
    6810           0 :       !fninfo->mFFITypes.reserve(args.length())) {
    6811           0 :     JS_ReportOutOfMemory(cx);
    6812           0 :     return false;
    6813             :   }
    6814             : 
    6815           0 :   fninfo->mIsVariadic = false;
    6816             : 
    6817           0 :   for (uint32_t i = 0; i < args.length(); ++i) {
    6818             :     bool isEllipsis;
    6819           0 :     if (!IsEllipsis(cx, args[i], &isEllipsis))
    6820           0 :       return false;
    6821           0 :     if (isEllipsis) {
    6822           0 :       fninfo->mIsVariadic = true;
    6823           0 :       if (i < 1) {
    6824             :         JS_ReportErrorASCII(cx, "\"...\" may not be the first and only parameter "
    6825           0 :                             "type of a variadic function declaration");
    6826           0 :         return false;
    6827             :       }
    6828           0 :       if (i < args.length() - 1) {
    6829             :         JS_ReportErrorASCII(cx, "\"...\" must be the last parameter type of a "
    6830           0 :                             "variadic function declaration");
    6831           0 :         return false;
    6832             :       }
    6833           0 :       if (GetABICode(fninfo->mABI) != ABI_DEFAULT) {
    6834             :         JS_ReportErrorASCII(cx, "Variadic functions must use the __cdecl calling "
    6835           0 :                             "convention");
    6836           0 :         return false;
    6837             :       }
    6838           0 :       break;
    6839             :     }
    6840             : 
    6841           0 :     JSObject* argType = PrepareType(cx, i, args[i]);
    6842           0 :     if (!argType)
    6843           0 :       return false;
    6844             : 
    6845           0 :     ffi_type* ffiType = CType::GetFFIType(cx, argType);
    6846           0 :     if (!ffiType)
    6847           0 :       return false;
    6848             : 
    6849           0 :     fninfo->mArgTypes.infallibleAppend(argType);
    6850           0 :     fninfo->mFFITypes.infallibleAppend(ffiType);
    6851             :   }
    6852             : 
    6853           0 :   if (fninfo->mIsVariadic) {
    6854             :     // wait to PrepareCIF until function is called
    6855           0 :     return true;
    6856             :   }
    6857             : 
    6858           0 :   if (!PrepareCIF(cx, fninfo))
    6859           0 :     return false;
    6860             : 
    6861           0 :   return true;
    6862             : }
    6863             : 
    6864             : bool
    6865           0 : FunctionType::Create(JSContext* cx, unsigned argc, Value* vp)
    6866             : {
    6867             :   // Construct and return a new FunctionType object.
    6868           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    6869           0 :   if (args.length() < 2 || args.length() > 3) {
    6870           0 :     return ArgumentLengthError(cx, "FunctionType", "two or three", "s");
    6871             :   }
    6872             : 
    6873           0 :   AutoValueVector argTypes(cx);
    6874           0 :   RootedObject arrayObj(cx, nullptr);
    6875             : 
    6876           0 :   if (args.length() == 3) {
    6877             :     // Prepare an array of Values for the arguments.
    6878             :     bool isArray;
    6879           0 :     if (!args[2].isObject()) {
    6880           0 :       isArray = false;
    6881             :     } else {
    6882           0 :       if (!JS_IsArrayObject(cx, args[2], &isArray))
    6883           0 :         return false;
    6884             :     }
    6885             : 
    6886           0 :     if (!isArray)
    6887           0 :       return ArgumentTypeMismatch(cx, "third ", "FunctionType", "an array");
    6888             : 
    6889           0 :     arrayObj = &args[2].toObject();
    6890             : 
    6891             :     uint32_t len;
    6892           0 :     ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len));
    6893             : 
    6894           0 :     if (!argTypes.resize(len)) {
    6895           0 :       JS_ReportOutOfMemory(cx);
    6896           0 :       return false;
    6897             :     }
    6898             :   }
    6899             : 
    6900             :   // Pull out the argument types from the array, if any.
    6901           0 :   MOZ_ASSERT_IF(argTypes.length(), arrayObj);
    6902           0 :   for (uint32_t i = 0; i < argTypes.length(); ++i) {
    6903           0 :     if (!JS_GetElement(cx, arrayObj, i, argTypes[i]))
    6904           0 :       return false;
    6905             :   }
    6906             : 
    6907           0 :   JSObject* result = CreateInternal(cx, args[0], args[1], argTypes);
    6908           0 :   if (!result)
    6909           0 :     return false;
    6910             : 
    6911           0 :   args.rval().setObject(*result);
    6912           0 :   return true;
    6913             : }
    6914             : 
    6915             : JSObject*
    6916           0 : FunctionType::CreateInternal(JSContext* cx,
    6917             :                              HandleValue abi,
    6918             :                              HandleValue rtype,
    6919             :                              const HandleValueArray& args)
    6920             : {
    6921             :   // Prepare the result type
    6922           0 :   RootedObject returnType(cx, PrepareReturnType(cx, rtype));
    6923           0 :   if (!returnType)
    6924           0 :     return nullptr;
    6925             : 
    6926             :   // Get ctypes.FunctionType.prototype and the common prototype for CData objects
    6927             :   // of this type, from ctypes.CType.prototype.
    6928           0 :   RootedObject typeProto(cx, CType::GetProtoFromType(cx, returnType, SLOT_FUNCTIONPROTO));
    6929           0 :   if (!typeProto)
    6930           0 :     return nullptr;
    6931           0 :   RootedObject dataProto(cx, CType::GetProtoFromType(cx, returnType, SLOT_FUNCTIONDATAPROTO));
    6932           0 :   if (!dataProto)
    6933           0 :     return nullptr;
    6934             : 
    6935             :   // Create a new CType object with the common properties and slots.
    6936           0 :   RootedObject typeObj(cx, CType::Create(cx, typeProto, dataProto, TYPE_function,
    6937             :                                          nullptr, JS::UndefinedHandleValue,
    6938           0 :                                          JS::UndefinedHandleValue, nullptr));
    6939           0 :   if (!typeObj)
    6940           0 :     return nullptr;
    6941             : 
    6942             :   // Determine and check the types, and prepare the function CIF.
    6943           0 :   if (!CreateFunctionInfo(cx, typeObj, abi, returnType, args))
    6944           0 :       return nullptr;
    6945             : 
    6946           0 :   return typeObj;
    6947             : }
    6948             : 
    6949             : // Construct a function pointer to a JS function (see CClosure::Create()).
    6950             : // Regular function pointers are constructed directly in
    6951             : // PointerType::ConstructData().
    6952             : bool
    6953           0 : FunctionType::ConstructData(JSContext* cx,
    6954             :                             HandleObject typeObj,
    6955             :                             HandleObject dataObj,
    6956             :                             HandleObject fnObj,
    6957             :                             HandleObject thisObj,
    6958             :                             HandleValue errVal)
    6959             : {
    6960           0 :   MOZ_ASSERT(CType::GetTypeCode(typeObj) == TYPE_function);
    6961             : 
    6962           0 :   PRFuncPtr* data = static_cast<PRFuncPtr*>(CData::GetData(dataObj));
    6963             : 
    6964           0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    6965           0 :   if (fninfo->mIsVariadic) {
    6966           0 :     JS_ReportErrorASCII(cx, "Can't declare a variadic callback function");
    6967           0 :     return false;
    6968             :   }
    6969           0 :   if (GetABICode(fninfo->mABI) == ABI_WINAPI) {
    6970             :     JS_ReportErrorASCII(cx, "Can't declare a ctypes.winapi_abi callback function, "
    6971           0 :                         "use ctypes.stdcall_abi instead");
    6972           0 :     return false;
    6973             :   }
    6974             : 
    6975           0 :   RootedObject closureObj(cx, CClosure::Create(cx, typeObj, fnObj, thisObj, errVal, data));
    6976           0 :   if (!closureObj)
    6977           0 :     return false;
    6978             : 
    6979             :   // Set the closure object as the referent of the new CData object.
    6980           0 :   JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*closureObj));
    6981             : 
    6982             :   // Seal the CData object, to prevent modification of the function pointer.
    6983             :   // This permanently associates this object with the closure, and avoids
    6984             :   // having to do things like reset SLOT_REFERENT when someone tries to
    6985             :   // change the pointer value.
    6986             :   // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
    6987             :   // could be called on a frozen object.
    6988           0 :   return JS_FreezeObject(cx, dataObj);
    6989             : }
    6990             : 
    6991             : typedef Vector<AutoValue, 16, SystemAllocPolicy> AutoValueAutoArray;
    6992             : 
    6993             : static bool
    6994           0 : ConvertArgument(JSContext* cx,
    6995             :                 HandleObject funObj,
    6996             :                 unsigned argIndex,
    6997             :                 HandleValue arg,
    6998             :                 JSObject* type,
    6999             :                 AutoValue* value,
    7000             :                 AutoValueAutoArray* strings)
    7001             : {
    7002           0 :   if (!value->SizeToType(cx, type)) {
    7003           0 :     JS_ReportAllocationOverflow(cx);
    7004           0 :     return false;
    7005             :   }
    7006             : 
    7007           0 :   bool freePointer = false;
    7008           0 :   if (!ImplicitConvert(cx, arg, type, value->mData,
    7009             :                        ConversionType::Argument, &freePointer,
    7010             :                        funObj, argIndex))
    7011           0 :     return false;
    7012             : 
    7013           0 :   if (freePointer) {
    7014             :     // ImplicitConvert converted a string for us, which we have to free.
    7015             :     // Keep track of it.
    7016           0 :     if (!strings->growBy(1)) {
    7017           0 :       JS_ReportOutOfMemory(cx);
    7018           0 :       return false;
    7019             :     }
    7020           0 :     strings->back().mData = *static_cast<char**>(value->mData);
    7021             :   }
    7022             : 
    7023           0 :   return true;
    7024             : }
    7025             : 
    7026             : bool
    7027           0 : FunctionType::Call(JSContext* cx,
    7028             :                    unsigned argc,
    7029             :                    Value* vp)
    7030             : {
    7031           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7032             :   // get the callee object...
    7033           0 :   RootedObject obj(cx, &args.callee());
    7034           0 :   if (!CData::IsCData(obj)) {
    7035           0 :     return IncompatibleThisProto(cx, "FunctionType.prototype.call",
    7036           0 :                                  args.calleev());
    7037             :   }
    7038             : 
    7039           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    7040           0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    7041           0 :     return IncompatibleThisType(cx, "FunctionType.prototype.call",
    7042           0 :                                 "non-PointerType CData", args.calleev());
    7043             :   }
    7044             : 
    7045           0 :   typeObj = PointerType::GetBaseType(typeObj);
    7046           0 :   if (CType::GetTypeCode(typeObj) != TYPE_function) {
    7047           0 :     return IncompatibleThisType(cx, "FunctionType.prototype.call",
    7048           0 :                                 "non-FunctionType pointer", args.calleev());
    7049             :   }
    7050             : 
    7051           0 :   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
    7052           0 :   uint32_t argcFixed = fninfo->mArgTypes.length();
    7053             : 
    7054           0 :   if ((!fninfo->mIsVariadic && args.length() != argcFixed) ||
    7055           0 :       (fninfo->mIsVariadic && args.length() < argcFixed)) {
    7056           0 :     return FunctionArgumentLengthMismatch(cx, argcFixed, args.length(),
    7057           0 :                                           obj, typeObj, fninfo->mIsVariadic);
    7058             :   }
    7059             : 
    7060             :   // Check if we have a Library object. If we do, make sure it's open.
    7061           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_REFERENT);
    7062           0 :   if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
    7063           0 :     PRLibrary* library = Library::GetLibrary(&slot.toObject());
    7064           0 :     if (!library) {
    7065           0 :       JS_ReportErrorASCII(cx, "library is not open");
    7066           0 :       return false;
    7067             :     }
    7068             :   }
    7069             : 
    7070             :   // prepare the values for each argument
    7071           0 :   AutoValueAutoArray values;
    7072           0 :   AutoValueAutoArray strings;
    7073           0 :   if (!values.resize(args.length())) {
    7074           0 :     JS_ReportOutOfMemory(cx);
    7075           0 :     return false;
    7076             :   }
    7077             : 
    7078           0 :   for (unsigned i = 0; i < argcFixed; ++i)
    7079           0 :     if (!ConvertArgument(cx, obj, i, args[i], fninfo->mArgTypes[i],
    7080           0 :                          &values[i], &strings))
    7081           0 :       return false;
    7082             : 
    7083           0 :   if (fninfo->mIsVariadic) {
    7084           0 :     if (!fninfo->mFFITypes.resize(args.length())) {
    7085           0 :       JS_ReportOutOfMemory(cx);
    7086           0 :       return false;
    7087             :     }
    7088             : 
    7089           0 :     RootedObject obj(cx);  // Could reuse obj instead of declaring a second
    7090           0 :     RootedObject type(cx); // RootedObject, but readability would suffer.
    7091             : 
    7092           0 :     for (uint32_t i = argcFixed; i < args.length(); ++i) {
    7093           0 :       if (args[i].isPrimitive() ||
    7094           0 :           !CData::IsCData(obj = &args[i].toObject())) {
    7095             :         // Since we know nothing about the CTypes of the ... arguments,
    7096             :         // they absolutely must be CData objects already.
    7097           0 :         return VariadicArgumentTypeError(cx, i, args[i]);
    7098             :       }
    7099           0 :       type = CData::GetCType(obj);
    7100           0 :       if (!type) {
    7101             :         // These functions report their own errors.
    7102           0 :         return false;
    7103             :       }
    7104           0 :       RootedValue typeVal(cx, ObjectValue(*type));
    7105           0 :       type = PrepareType(cx, i, typeVal);
    7106           0 :       if (!type) {
    7107           0 :         return false;
    7108             :       }
    7109             :       // Relying on ImplicitConvert only for the limited purpose of
    7110             :       // converting one CType to another (e.g., T[] to T*).
    7111           0 :       if (!ConvertArgument(cx, obj, i, args[i], type, &values[i], &strings)) {
    7112           0 :         return false;
    7113             :       }
    7114           0 :       fninfo->mFFITypes[i] = CType::GetFFIType(cx, type);
    7115           0 :       if (!fninfo->mFFITypes[i]) {
    7116           0 :         return false;
    7117             :       }
    7118             :     }
    7119           0 :     if (!PrepareCIF(cx, fninfo))
    7120           0 :       return false;
    7121             :   }
    7122             : 
    7123             :   // initialize a pointer to an appropriate location, for storing the result
    7124           0 :   AutoValue returnValue;
    7125           0 :   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
    7126           0 :   if (typeCode != TYPE_void_t &&
    7127           0 :       !returnValue.SizeToType(cx, fninfo->mReturnType)) {
    7128           0 :     JS_ReportAllocationOverflow(cx);
    7129           0 :     return false;
    7130             :   }
    7131             : 
    7132             :   // Let the runtime callback know that we are about to call into C.
    7133           0 :   js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALL_BEGIN, js::CTYPES_CALL_END);
    7134             : 
    7135           0 :   uintptr_t fn = *reinterpret_cast<uintptr_t*>(CData::GetData(obj));
    7136             : 
    7137             : #if defined(XP_WIN)
    7138             :   int32_t lastErrorStatus; // The status as defined by |GetLastError|
    7139             :   int32_t savedLastError = GetLastError();
    7140             :   SetLastError(0);
    7141             : #endif //defined(XP_WIN)
    7142             :   int errnoStatus;         // The status as defined by |errno|
    7143           0 :   int savedErrno = errno;
    7144           0 :   errno = 0;
    7145             : 
    7146           0 :   ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData,
    7147           0 :            reinterpret_cast<void**>(values.begin()));
    7148             : 
    7149             :   // Save error value.
    7150             :   // We need to save it before leaving the scope of |suspend| as destructing
    7151             :   // |suspend| has the side-effect of clearing |GetLastError|
    7152             :   // (see bug 684017).
    7153             : 
    7154           0 :   errnoStatus = errno;
    7155             : #if defined(XP_WIN)
    7156             :   lastErrorStatus = GetLastError();
    7157             :   SetLastError(savedLastError);
    7158             : #endif // defined(XP_WIN)
    7159             : 
    7160           0 :   errno = savedErrno;
    7161             : 
    7162             :   // We're no longer calling into C.
    7163           0 :   autoCallback.DoEndCallback();
    7164             : 
    7165             :   // Store the error value for later consultation with |ctypes.getStatus|
    7166           0 :   JSObject* objCTypes = CType::GetGlobalCTypes(cx, typeObj);
    7167           0 :   if (!objCTypes)
    7168           0 :     return false;
    7169             : 
    7170           0 :   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, Int32Value(errnoStatus));
    7171             : #if defined(XP_WIN)
    7172             :   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, Int32Value(lastErrorStatus));
    7173             : #endif // defined(XP_WIN)
    7174             : 
    7175             :   // Small integer types get returned as a word-sized ffi_arg. Coerce it back
    7176             :   // into the correct size for ConvertToJS.
    7177           0 :   switch (typeCode) {
    7178             : #define INTEGRAL_CASE(name, type, ffiType)                                     \
    7179             :   case TYPE_##name:                                                            \
    7180             :     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
    7181             :       ffi_arg data = *static_cast<ffi_arg*>(returnValue.mData);                \
    7182             :       *static_cast<type*>(returnValue.mData) = static_cast<type>(data);        \
    7183             :     }                                                                          \
    7184             :     break;
    7185           0 :   CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    7186           0 :   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
    7187           0 :   CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
    7188           0 :   CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
    7189           0 :   CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
    7190             : #undef INTEGRAL_CASE
    7191             :   default:
    7192           0 :     break;
    7193             :   }
    7194             : 
    7195             :   // prepare a JS object from the result
    7196           0 :   RootedObject returnType(cx, fninfo->mReturnType);
    7197           0 :   return ConvertToJS(cx, returnType, nullptr, returnValue.mData, false, true, args.rval());
    7198             : }
    7199             : 
    7200             : FunctionInfo*
    7201           0 : FunctionType::GetFunctionInfo(JSObject* obj)
    7202             : {
    7203           0 :   MOZ_ASSERT(CType::IsCType(obj));
    7204           0 :   MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_function);
    7205             : 
    7206           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
    7207           0 :   MOZ_ASSERT(!slot.isUndefined() && slot.toPrivate());
    7208             : 
    7209           0 :   return static_cast<FunctionInfo*>(slot.toPrivate());
    7210             : }
    7211             : 
    7212             : bool
    7213           0 : FunctionType::IsFunctionType(HandleValue v)
    7214             : {
    7215           0 :   if (!v.isObject())
    7216           0 :     return false;
    7217           0 :   JSObject* obj = &v.toObject();
    7218           0 :   return CType::IsCType(obj) && CType::GetTypeCode(obj) == TYPE_function;
    7219             : }
    7220             : 
    7221             : bool
    7222           0 : FunctionType::ArgTypesGetter(JSContext* cx, const JS::CallArgs& args)
    7223             : {
    7224           0 :   JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
    7225             : 
    7226           0 :   args.rval().set(JS_GetReservedSlot(obj, SLOT_ARGS_T));
    7227           0 :   if (!args.rval().isUndefined())
    7228           0 :     return true;
    7229             : 
    7230           0 :   FunctionInfo* fninfo = GetFunctionInfo(obj);
    7231           0 :   size_t len = fninfo->mArgTypes.length();
    7232             : 
    7233             :   // Prepare a new array.
    7234           0 :   JS::Rooted<JSObject*> argTypes(cx);
    7235             :   {
    7236           0 :       JS::AutoValueVector vec(cx);
    7237           0 :       if (!vec.resize(len))
    7238           0 :         return false;
    7239             : 
    7240           0 :       for (size_t i = 0; i < len; ++i)
    7241           0 :         vec[i].setObject(*fninfo->mArgTypes[i]);
    7242             : 
    7243           0 :       argTypes = JS_NewArrayObject(cx, vec);
    7244           0 :       if (!argTypes)
    7245           0 :         return false;
    7246             :   }
    7247             : 
    7248             :   // Seal and cache it.
    7249           0 :   if (!JS_FreezeObject(cx, argTypes))
    7250           0 :     return false;
    7251           0 :   JS_SetReservedSlot(obj, SLOT_ARGS_T, JS::ObjectValue(*argTypes));
    7252             : 
    7253           0 :   args.rval().setObject(*argTypes);
    7254           0 :   return true;
    7255             : }
    7256             : 
    7257             : bool
    7258           0 : FunctionType::ReturnTypeGetter(JSContext* cx, const JS::CallArgs& args)
    7259             : {
    7260             :   // Get the returnType object from the FunctionInfo.
    7261           0 :   args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mReturnType);
    7262           0 :   return true;
    7263             : }
    7264             : 
    7265             : bool
    7266           0 : FunctionType::ABIGetter(JSContext* cx, const JS::CallArgs& args)
    7267             : {
    7268             :   // Get the abi object from the FunctionInfo.
    7269           0 :   args.rval().setObject(*GetFunctionInfo(&args.thisv().toObject())->mABI);
    7270           0 :   return true;
    7271             : }
    7272             : 
    7273             : bool
    7274           0 : FunctionType::IsVariadicGetter(JSContext* cx, const JS::CallArgs& args)
    7275             : {
    7276           0 :   args.rval().setBoolean(GetFunctionInfo(&args.thisv().toObject())->mIsVariadic);
    7277           0 :   return true;
    7278             : }
    7279             : 
    7280             : /*******************************************************************************
    7281             : ** CClosure implementation
    7282             : *******************************************************************************/
    7283             : 
    7284             : JSObject*
    7285           0 : CClosure::Create(JSContext* cx,
    7286             :                  HandleObject typeObj,
    7287             :                  HandleObject fnObj,
    7288             :                  HandleObject thisObj,
    7289             :                  HandleValue errVal,
    7290             :                  PRFuncPtr* fnptr)
    7291             : {
    7292           0 :   MOZ_ASSERT(fnObj);
    7293             : 
    7294           0 :   RootedObject result(cx, JS_NewObject(cx, &sCClosureClass));
    7295           0 :   if (!result)
    7296           0 :     return nullptr;
    7297             : 
    7298             :   // Get the FunctionInfo from the FunctionType.
    7299           0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    7300           0 :   MOZ_ASSERT(!fninfo->mIsVariadic);
    7301           0 :   MOZ_ASSERT(GetABICode(fninfo->mABI) != ABI_WINAPI);
    7302             : 
    7303             :   // Get the prototype of the FunctionType object, of class CTypeProto,
    7304             :   // which stores our JSContext for use with the closure.
    7305           0 :   RootedObject proto(cx);
    7306           0 :   if (!JS_GetPrototype(cx, typeObj, &proto))
    7307           0 :     return nullptr;
    7308           0 :   MOZ_ASSERT(proto);
    7309           0 :   MOZ_ASSERT(CType::IsCTypeProto(proto));
    7310             : 
    7311             :   // Prepare the error sentinel value. It's important to do this now, because
    7312             :   // we might be unable to convert the value to the proper type. If so, we want
    7313             :   // the caller to know about it _now_, rather than some uncertain time in the
    7314             :   // future when the error sentinel is actually needed.
    7315           0 :   UniquePtr<uint8_t[], JS::FreePolicy> errResult;
    7316           0 :   if (!errVal.isUndefined()) {
    7317             : 
    7318             :     // Make sure the callback returns something.
    7319           0 :     if (CType::GetTypeCode(fninfo->mReturnType) == TYPE_void_t) {
    7320           0 :       JS_ReportErrorASCII(cx, "A void callback can't pass an error sentinel");
    7321           0 :       return nullptr;
    7322             :     }
    7323             : 
    7324             :     // With the exception of void, the FunctionType constructor ensures that
    7325             :     // the return type has a defined size.
    7326           0 :     MOZ_ASSERT(CType::IsSizeDefined(fninfo->mReturnType));
    7327             : 
    7328             :     // Allocate a buffer for the return value.
    7329           0 :     size_t rvSize = CType::GetSize(fninfo->mReturnType);
    7330           0 :     errResult = result->zone()->make_pod_array<uint8_t>(rvSize);
    7331           0 :     if (!errResult)
    7332           0 :       return nullptr;
    7333             : 
    7334             :     // Do the value conversion. This might fail, in which case we throw.
    7335           0 :     if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, errResult.get(),
    7336           0 :                          ConversionType::Return, nullptr, typeObj))
    7337           0 :       return nullptr;
    7338             :   }
    7339             : 
    7340           0 :   ClosureInfo* cinfo = cx->new_<ClosureInfo>(cx);
    7341           0 :   if (!cinfo) {
    7342           0 :     JS_ReportOutOfMemory(cx);
    7343           0 :     return nullptr;
    7344             :   }
    7345             : 
    7346             :   // Copy the important bits of context into cinfo.
    7347           0 :   cinfo->errResult = errResult.release();
    7348           0 :   cinfo->closureObj = result;
    7349           0 :   cinfo->typeObj = typeObj;
    7350           0 :   cinfo->thisObj = thisObj;
    7351           0 :   cinfo->jsfnObj = fnObj;
    7352             : 
    7353             :   // Stash the ClosureInfo struct on our new object.
    7354           0 :   JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PrivateValue(cinfo));
    7355             : 
    7356             :   // Create an ffi_closure object and initialize it.
    7357             :   void* code;
    7358           0 :   cinfo->closure =
    7359           0 :     static_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &code));
    7360           0 :   if (!cinfo->closure || !code) {
    7361           0 :     JS_ReportErrorASCII(cx, "couldn't create closure - libffi error");
    7362           0 :     return nullptr;
    7363             :   }
    7364             : 
    7365           0 :   ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF,
    7366           0 :     CClosure::ClosureStub, cinfo, code);
    7367           0 :   if (status != FFI_OK) {
    7368           0 :     JS_ReportErrorASCII(cx, "couldn't create closure - libffi error");
    7369           0 :     return nullptr;
    7370             :   }
    7371             : 
    7372             :   // Casting between void* and a function pointer is forbidden in C and C++.
    7373             :   // Do it via an integral type.
    7374           0 :   *fnptr = reinterpret_cast<PRFuncPtr>(reinterpret_cast<uintptr_t>(code));
    7375           0 :   return result;
    7376             : }
    7377             : 
    7378             : void
    7379           0 : CClosure::Trace(JSTracer* trc, JSObject* obj)
    7380             : {
    7381             :   // Make sure our ClosureInfo slot is legit. If it's not, bail.
    7382           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
    7383           0 :   if (slot.isUndefined())
    7384           0 :     return;
    7385             : 
    7386           0 :   ClosureInfo* cinfo = static_cast<ClosureInfo*>(slot.toPrivate());
    7387             : 
    7388             :   // Identify our objects to the tracer. (There's no need to identify
    7389             :   // 'closureObj', since that's us.)
    7390           0 :   JS::TraceEdge(trc, &cinfo->typeObj, "typeObj");
    7391           0 :   JS::TraceEdge(trc, &cinfo->jsfnObj, "jsfnObj");
    7392           0 :   if (cinfo->thisObj)
    7393           0 :     JS::TraceEdge(trc, &cinfo->thisObj, "thisObj");
    7394             : }
    7395             : 
    7396             : void
    7397           0 : CClosure::Finalize(JSFreeOp* fop, JSObject* obj)
    7398             : {
    7399             :   // Make sure our ClosureInfo slot is legit. If it's not, bail.
    7400           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
    7401           0 :   if (slot.isUndefined())
    7402           0 :     return;
    7403             : 
    7404           0 :   ClosureInfo* cinfo = static_cast<ClosureInfo*>(slot.toPrivate());
    7405           0 :   FreeOp::get(fop)->delete_(cinfo);
    7406             : }
    7407             : 
    7408             : void
    7409           0 : CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
    7410             : {
    7411           0 :   MOZ_ASSERT(cif);
    7412           0 :   MOZ_ASSERT(result);
    7413           0 :   MOZ_ASSERT(args);
    7414           0 :   MOZ_ASSERT(userData);
    7415             : 
    7416             :   // Retrieve the essentials from our closure object.
    7417           0 :   ArgClosure argClosure(cif, result, args, static_cast<ClosureInfo*>(userData));
    7418           0 :   JSContext* cx = argClosure.cinfo->cx;
    7419           0 :   RootedObject fun(cx, argClosure.cinfo->jsfnObj);
    7420             : 
    7421           0 :   js::PrepareScriptEnvironmentAndInvoke(cx, fun, argClosure);
    7422           0 : }
    7423             : 
    7424           0 : bool CClosure::ArgClosure::operator()(JSContext* cx)
    7425             : {
    7426             :   // Let the runtime callback know that we are about to call into JS again. The end callback will
    7427             :   // fire automatically when we exit this function.
    7428             :   js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
    7429           0 :                                               js::CTYPES_CALLBACK_END);
    7430             : 
    7431           0 :   RootedObject typeObj(cx, cinfo->typeObj);
    7432           0 :   RootedObject thisObj(cx, cinfo->thisObj);
    7433           0 :   RootedValue jsfnVal(cx, ObjectValue(*cinfo->jsfnObj));
    7434           0 :   AssertSameCompartment(cx, cinfo->jsfnObj);
    7435             : 
    7436             : 
    7437           0 :   JS_AbortIfWrongThread(cx);
    7438             : 
    7439             :   // Assert that our CIFs agree.
    7440           0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    7441           0 :   MOZ_ASSERT(cif == &fninfo->mCIF);
    7442             : 
    7443           0 :   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
    7444             : 
    7445             :   // Initialize the result to zero, in case something fails. Small integer types
    7446             :   // are promoted to a word-sized ffi_arg, so we must be careful to zero the
    7447             :   // whole word.
    7448           0 :   size_t rvSize = 0;
    7449           0 :   if (cif->rtype != &ffi_type_void) {
    7450           0 :     rvSize = cif->rtype->size;
    7451           0 :     switch (typeCode) {
    7452             : #define INTEGRAL_CASE(name, type, ffiType)  case TYPE_##name:
    7453             :     CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    7454             :     CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
    7455             :     CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
    7456             :     CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
    7457             :     CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
    7458             : #undef INTEGRAL_CASE
    7459           0 :       rvSize = Align(rvSize, sizeof(ffi_arg));
    7460           0 :       break;
    7461             :     default:
    7462           0 :       break;
    7463             :     }
    7464           0 :     memset(result, 0, rvSize);
    7465             :   }
    7466             : 
    7467             :   // Set up an array for converted arguments.
    7468           0 :   JS::AutoValueVector argv(cx);
    7469           0 :   if (!argv.resize(cif->nargs)) {
    7470           0 :     JS_ReportOutOfMemory(cx);
    7471           0 :     return false;
    7472             :   }
    7473             : 
    7474           0 :   for (uint32_t i = 0; i < cif->nargs; ++i) {
    7475             :     // Convert each argument, and have any CData objects created depend on
    7476             :     // the existing buffers.
    7477           0 :     RootedObject argType(cx, fninfo->mArgTypes[i]);
    7478           0 :     if (!ConvertToJS(cx, argType, nullptr, args[i], false, false, argv[i]))
    7479           0 :       return false;
    7480             :   }
    7481             : 
    7482             :   // Call the JS function. 'thisObj' may be nullptr, in which case the JS
    7483             :   // engine will find an appropriate object to use.
    7484           0 :   RootedValue rval(cx);
    7485           0 :   bool success = JS_CallFunctionValue(cx, thisObj, jsfnVal, argv, &rval);
    7486             : 
    7487             :   // Convert the result. Note that we pass 'ConversionType::Return', such that
    7488             :   // ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char
    7489             :   // type, which would require an allocation that we can't track. The JS
    7490             :   // function must perform this conversion itself and return a PointerType
    7491             :   // CData; thusly, the burden of freeing the data is left to the user.
    7492           0 :   if (success && cif->rtype != &ffi_type_void)
    7493           0 :     success = ImplicitConvert(cx, rval, fninfo->mReturnType, result,
    7494           0 :                               ConversionType::Return, nullptr, typeObj);
    7495             : 
    7496           0 :   if (!success) {
    7497             :     // Something failed. The callee may have thrown, or it may not have
    7498             :     // returned a value that ImplicitConvert() was happy with. Depending on how
    7499             :     // prudent the consumer has been, we may or may not have a recovery plan.
    7500             :     //
    7501             :     // Note that PrepareScriptEnvironmentAndInvoke should take care of reporting
    7502             :     // the exception.
    7503             : 
    7504           0 :     if (cinfo->errResult) {
    7505             :       // Good case: we have a sentinel that we can return. Copy it in place of
    7506             :       // the actual return value, and then proceed.
    7507             : 
    7508             :       // The buffer we're returning might be larger than the size of the return
    7509             :       // type, due to libffi alignment issues (see above). But it should never
    7510             :       // be smaller.
    7511           0 :       size_t copySize = CType::GetSize(fninfo->mReturnType);
    7512           0 :       MOZ_ASSERT(copySize <= rvSize);
    7513           0 :       memcpy(result, cinfo->errResult, copySize);
    7514             : 
    7515             :       // We still want to return false here, so that
    7516             :       // PrepareScriptEnvironmentAndInvoke will report the exception.
    7517             :     } else {
    7518             :       // Bad case: not much we can do here. The rv is already zeroed out, so we
    7519             :       // just return and hope for the best.
    7520             :     }
    7521           0 :     return false;
    7522             :   }
    7523             : 
    7524             :   // Small integer types must be returned as a word-sized ffi_arg. Coerce it
    7525             :   // back into the size libffi expects.
    7526           0 :   switch (typeCode) {
    7527             : #define INTEGRAL_CASE(name, type, ffiType)                                     \
    7528             :   case TYPE_##name:                                                            \
    7529             :     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
    7530             :       ffi_arg data = *static_cast<type*>(result);                              \
    7531             :       *static_cast<ffi_arg*>(result) = data;                                   \
    7532             :     }                                                                          \
    7533             :     break;
    7534           0 :     CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
    7535           0 :     CTYPES_FOR_EACH_WRAPPED_INT_TYPE(INTEGRAL_CASE)
    7536           0 :     CTYPES_FOR_EACH_BOOL_TYPE(INTEGRAL_CASE)
    7537           0 :     CTYPES_FOR_EACH_CHAR_TYPE(INTEGRAL_CASE)
    7538           0 :     CTYPES_FOR_EACH_CHAR16_TYPE(INTEGRAL_CASE)
    7539             : #undef INTEGRAL_CASE
    7540             :   default:
    7541           0 :     break;
    7542             :   }
    7543             : 
    7544           0 :   return true;
    7545             : }
    7546             : 
    7547             : /*******************************************************************************
    7548             : ** CData implementation
    7549             : *******************************************************************************/
    7550             : 
    7551             : // Create a new CData object of type 'typeObj' containing binary data supplied
    7552             : // in 'source', optionally with a referent object 'refObj'.
    7553             : //
    7554             : // * 'typeObj' must be a CType of defined (but possibly zero) size.
    7555             : //
    7556             : // * If an object 'refObj' is supplied, the new CData object stores the
    7557             : //   referent object in a reserved slot for GC safety, such that 'refObj' will
    7558             : //   be held alive by the resulting CData object. 'refObj' may or may not be
    7559             : //   a CData object; merely an object we want to keep alive.
    7560             : //   * If 'refObj' is a CData object, 'ownResult' must be false.
    7561             : //   * Otherwise, 'refObj' is a Library or CClosure object, and 'ownResult'
    7562             : //     may be true or false.
    7563             : // * Otherwise 'refObj' is nullptr. In this case, 'ownResult' may be true or
    7564             : //   false.
    7565             : //
    7566             : // * If 'ownResult' is true, the CData object will allocate an appropriately
    7567             : //   sized buffer, and free it upon finalization. If 'source' data is
    7568             : //   supplied, the data will be copied from 'source' into the buffer;
    7569             : //   otherwise, the entirety of the new buffer will be initialized to zero.
    7570             : // * If 'ownResult' is false, the new CData's buffer refers to a slice of
    7571             : //   another buffer kept alive by 'refObj'. 'source' data must be provided,
    7572             : //   and the new CData's buffer will refer to 'source'.
    7573             : JSObject*
    7574           0 : CData::Create(JSContext* cx,
    7575             :               HandleObject typeObj,
    7576             :               HandleObject refObj,
    7577             :               void* source,
    7578             :               bool ownResult)
    7579             : {
    7580           0 :   MOZ_ASSERT(typeObj);
    7581           0 :   MOZ_ASSERT(CType::IsCType(typeObj));
    7582           0 :   MOZ_ASSERT(CType::IsSizeDefined(typeObj));
    7583           0 :   MOZ_ASSERT(ownResult || source);
    7584           0 :   MOZ_ASSERT_IF(refObj && CData::IsCData(refObj), !ownResult);
    7585             : 
    7586             :   // Get the 'prototype' property from the type.
    7587           0 :   Value slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
    7588           0 :   MOZ_ASSERT(slot.isObject());
    7589             : 
    7590           0 :   RootedObject proto(cx, &slot.toObject());
    7591             : 
    7592           0 :   RootedObject dataObj(cx, JS_NewObjectWithGivenProto(cx, &sCDataClass, proto));
    7593           0 :   if (!dataObj)
    7594           0 :     return nullptr;
    7595             : 
    7596             :   // set the CData's associated type
    7597           0 :   JS_SetReservedSlot(dataObj, SLOT_CTYPE, ObjectValue(*typeObj));
    7598             : 
    7599             :   // Stash the referent object, if any, for GC safety.
    7600           0 :   if (refObj)
    7601           0 :     JS_SetReservedSlot(dataObj, SLOT_REFERENT, ObjectValue(*refObj));
    7602             : 
    7603             :   // Set our ownership flag.
    7604           0 :   JS_SetReservedSlot(dataObj, SLOT_OWNS, BooleanValue(ownResult));
    7605             : 
    7606             :   // attach the buffer. since it might not be 2-byte aligned, we need to
    7607             :   // allocate an aligned space for it and store it there. :(
    7608           0 :   char** buffer = cx->new_<char*>();
    7609           0 :   if (!buffer) {
    7610           0 :     JS_ReportOutOfMemory(cx);
    7611           0 :     return nullptr;
    7612             :   }
    7613             : 
    7614             :   char* data;
    7615           0 :   if (!ownResult) {
    7616           0 :     data = static_cast<char*>(source);
    7617             :   } else {
    7618             :     // Initialize our own buffer.
    7619           0 :     size_t size = CType::GetSize(typeObj);
    7620           0 :     data = dataObj->zone()->pod_malloc<char>(size);
    7621           0 :     if (!data) {
    7622             :       // Report a catchable allocation error.
    7623           0 :       JS_ReportAllocationOverflow(cx);
    7624           0 :       js_free(buffer);
    7625           0 :       return nullptr;
    7626             :     }
    7627             : 
    7628           0 :     if (!source)
    7629           0 :       memset(data, 0, size);
    7630             :     else
    7631           0 :       memcpy(data, source, size);
    7632             :   }
    7633             : 
    7634           0 :   *buffer = data;
    7635           0 :   JS_SetReservedSlot(dataObj, SLOT_DATA, PrivateValue(buffer));
    7636             : 
    7637           0 :   return dataObj;
    7638             : }
    7639             : 
    7640             : void
    7641           0 : CData::Finalize(JSFreeOp* fop, JSObject* obj)
    7642             : {
    7643             :   // Delete our buffer, and the data it contains if we own it.
    7644           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_OWNS);
    7645           0 :   if (slot.isUndefined())
    7646           0 :     return;
    7647             : 
    7648           0 :   bool owns = slot.toBoolean();
    7649             : 
    7650           0 :   slot = JS_GetReservedSlot(obj, SLOT_DATA);
    7651           0 :   if (slot.isUndefined())
    7652           0 :     return;
    7653           0 :   char** buffer = static_cast<char**>(slot.toPrivate());
    7654             : 
    7655           0 :   if (owns)
    7656           0 :     FreeOp::get(fop)->free_(*buffer);
    7657           0 :   FreeOp::get(fop)->delete_(buffer);
    7658             : }
    7659             : 
    7660             : JSObject*
    7661           0 : CData::GetCType(JSObject* dataObj)
    7662             : {
    7663           0 :   MOZ_ASSERT(CData::IsCData(dataObj));
    7664             : 
    7665           0 :   Value slot = JS_GetReservedSlot(dataObj, SLOT_CTYPE);
    7666           0 :   JSObject* typeObj = slot.toObjectOrNull();
    7667           0 :   MOZ_ASSERT(CType::IsCType(typeObj));
    7668           0 :   return typeObj;
    7669             : }
    7670             : 
    7671             : void*
    7672           0 : CData::GetData(JSObject* dataObj)
    7673             : {
    7674           0 :   MOZ_ASSERT(CData::IsCData(dataObj));
    7675             : 
    7676           0 :   Value slot = JS_GetReservedSlot(dataObj, SLOT_DATA);
    7677             : 
    7678           0 :   void** buffer = static_cast<void**>(slot.toPrivate());
    7679           0 :   MOZ_ASSERT(buffer);
    7680           0 :   MOZ_ASSERT(*buffer);
    7681           0 :   return *buffer;
    7682             : }
    7683             : 
    7684             : bool
    7685           0 : CData::IsCData(JSObject* obj)
    7686             : {
    7687           0 :   return JS_GetClass(obj) == &sCDataClass;
    7688             : }
    7689             : 
    7690             : bool
    7691           0 : CData::IsCData(HandleValue v)
    7692             : {
    7693           0 :   return v.isObject() && CData::IsCData(&v.toObject());
    7694             : }
    7695             : 
    7696             : bool
    7697           0 : CData::IsCDataProto(JSObject* obj)
    7698             : {
    7699           0 :   return JS_GetClass(obj) == &sCDataProtoClass;
    7700             : }
    7701             : 
    7702             : bool
    7703           0 : CData::ValueGetter(JSContext* cx, const JS::CallArgs& args)
    7704             : {
    7705           0 :   RootedObject obj(cx, &args.thisv().toObject());
    7706             : 
    7707             :   // Convert the value to a primitive; do not create a new CData object.
    7708           0 :   RootedObject ctype(cx, GetCType(obj));
    7709           0 :   return ConvertToJS(cx, ctype, nullptr, GetData(obj), true, false, args.rval());
    7710             : }
    7711             : 
    7712             : bool
    7713           0 : CData::ValueSetter(JSContext* cx, const JS::CallArgs& args)
    7714             : {
    7715           0 :   RootedObject obj(cx, &args.thisv().toObject());
    7716           0 :   args.rval().setUndefined();
    7717           0 :   return ImplicitConvert(cx, args.get(0), GetCType(obj), GetData(obj),
    7718           0 :                          ConversionType::Setter, nullptr);
    7719             : }
    7720             : 
    7721             : bool
    7722           0 : CData::Address(JSContext* cx, unsigned argc, Value* vp)
    7723             : {
    7724           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7725           0 :   if (args.length() != 0) {
    7726           0 :     return ArgumentLengthError(cx, "CData.prototype.address", "no", "s");
    7727             :   }
    7728             : 
    7729           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    7730           0 :   if (!obj)
    7731           0 :     return false;
    7732           0 :   if (!IsCData(obj)) {
    7733           0 :     return IncompatibleThisProto(cx, "CData.prototype.address", args.thisv());
    7734             :   }
    7735             : 
    7736           0 :   RootedObject typeObj(cx, CData::GetCType(obj));
    7737           0 :   RootedObject pointerType(cx, PointerType::CreateInternal(cx, typeObj));
    7738           0 :   if (!pointerType)
    7739           0 :     return false;
    7740             : 
    7741             :   // Create a PointerType CData object containing null.
    7742           0 :   JSObject* result = CData::Create(cx, pointerType, nullptr, nullptr, true);
    7743           0 :   if (!result)
    7744           0 :     return false;
    7745             : 
    7746           0 :   args.rval().setObject(*result);
    7747             : 
    7748             :   // Manually set the pointer inside the object, so we skip the conversion step.
    7749           0 :   void** data = static_cast<void**>(GetData(result));
    7750           0 :   *data = GetData(obj);
    7751           0 :   return true;
    7752             : }
    7753             : 
    7754             : bool
    7755           0 : CData::Cast(JSContext* cx, unsigned argc, Value* vp)
    7756             : {
    7757           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7758           0 :   if (args.length() != 2) {
    7759           0 :     return ArgumentLengthError(cx, "ctypes.cast", "two", "s");
    7760             :   }
    7761             : 
    7762           0 :   if (args[0].isPrimitive() || !CData::IsCData(&args[0].toObject())) {
    7763           0 :     return ArgumentTypeMismatch(cx, "first ", "ctypes.cast", "a CData");
    7764             :   }
    7765           0 :   RootedObject sourceData(cx, &args[0].toObject());
    7766           0 :   RootedObject sourceType(cx, CData::GetCType(sourceData));
    7767             : 
    7768           0 :   if (args[1].isPrimitive() || !CType::IsCType(&args[1].toObject())) {
    7769           0 :     return ArgumentTypeMismatch(cx, "second ", "ctypes.cast", "a CType");
    7770             :   }
    7771             : 
    7772           0 :   RootedObject targetType(cx, &args[1].toObject());
    7773             :   size_t targetSize;
    7774           0 :   if (!CType::GetSafeSize(targetType, &targetSize)) {
    7775           0 :     return UndefinedSizeCastError(cx, targetType);
    7776             :   }
    7777           0 :   if (targetSize > CType::GetSize(sourceType)) {
    7778           0 :     return SizeMismatchCastError(cx, sourceType, targetType,
    7779           0 :                                  CType::GetSize(sourceType), targetSize);
    7780             :   }
    7781             : 
    7782             :   // Construct a new CData object with a type of 'targetType' and a referent
    7783             :   // of 'sourceData'.
    7784           0 :   void* data = CData::GetData(sourceData);
    7785           0 :   JSObject* result = CData::Create(cx, targetType, sourceData, data, false);
    7786           0 :   if (!result)
    7787           0 :     return false;
    7788             : 
    7789           0 :   args.rval().setObject(*result);
    7790           0 :   return true;
    7791             : }
    7792             : 
    7793             : bool
    7794           0 : CData::GetRuntime(JSContext* cx, unsigned argc, Value* vp)
    7795             : {
    7796           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7797           0 :   if (args.length() != 1) {
    7798           0 :     return ArgumentLengthError(cx, "ctypes.getRuntime", "one", "");
    7799             :   }
    7800             : 
    7801           0 :   if (args[0].isPrimitive() || !CType::IsCType(&args[0].toObject())) {
    7802           0 :     return ArgumentTypeMismatch(cx, "", "ctypes.getRuntime", "a CType");
    7803             :   }
    7804             : 
    7805           0 :   RootedObject targetType(cx, &args[0].toObject());
    7806             :   size_t targetSize;
    7807           0 :   if (!CType::GetSafeSize(targetType, &targetSize) ||
    7808           0 :       targetSize != sizeof(void*)) {
    7809           0 :     JS_ReportErrorASCII(cx, "target CType has non-pointer size");
    7810           0 :     return false;
    7811             :   }
    7812             : 
    7813           0 :   void* data = static_cast<void*>(cx->runtime());
    7814           0 :   JSObject* result = CData::Create(cx, targetType, nullptr, &data, true);
    7815           0 :   if (!result)
    7816           0 :     return false;
    7817             : 
    7818           0 :   args.rval().setObject(*result);
    7819           0 :   return true;
    7820             : }
    7821             : 
    7822             : typedef JS::TwoByteCharsZ (*InflateUTF8Method)(JSContext*, const JS::UTF8Chars, size_t*);
    7823             : 
    7824             : static bool
    7825           0 : ReadStringCommon(JSContext* cx, InflateUTF8Method inflateUTF8, unsigned argc,
    7826             :                  Value* vp, const char* funName)
    7827             : {
    7828           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7829           0 :   if (args.length() != 0) {
    7830           0 :     return ArgumentLengthError(cx, funName, "no", "s");
    7831             :   }
    7832             : 
    7833           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    7834           0 :   if (!obj) {
    7835           0 :     return IncompatibleThisProto(cx, funName, args.thisv());
    7836             :   }
    7837           0 :   if (!CData::IsCData(obj)) {
    7838           0 :       if (!CDataFinalizer::IsCDataFinalizer(obj)) {
    7839           0 :           return IncompatibleThisProto(cx, funName, args.thisv());
    7840             :       }
    7841             : 
    7842             :       CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    7843           0 :                                    JS_GetPrivate(obj);
    7844           0 :       if (!p) {
    7845           0 :           return EmptyFinalizerCallError(cx, funName);
    7846             :       }
    7847             : 
    7848           0 :       RootedValue dataVal(cx);
    7849           0 :       if (!CDataFinalizer::GetValue(cx, obj, &dataVal)) {
    7850           0 :           return IncompatibleThisProto(cx, funName, args.thisv());
    7851             :       }
    7852             : 
    7853           0 :       if (dataVal.isPrimitive()) {
    7854           0 :           return IncompatibleThisProto(cx, funName, args.thisv());
    7855             :       }
    7856             : 
    7857           0 :       obj = dataVal.toObjectOrNull();
    7858           0 :       if (!obj || !CData::IsCData(obj)) {
    7859           0 :           return IncompatibleThisProto(cx, funName, args.thisv());
    7860             :       }
    7861             :   }
    7862             : 
    7863             :   // Make sure we are a pointer to, or an array of, an 8-bit or 16-bit
    7864             :   // character or integer type.
    7865             :   JSObject* baseType;
    7866           0 :   JSObject* typeObj = CData::GetCType(obj);
    7867           0 :   TypeCode typeCode = CType::GetTypeCode(typeObj);
    7868             :   void* data;
    7869           0 :   size_t maxLength = -1;
    7870           0 :   switch (typeCode) {
    7871             :   case TYPE_pointer:
    7872           0 :     baseType = PointerType::GetBaseType(typeObj);
    7873           0 :     data = *static_cast<void**>(CData::GetData(obj));
    7874           0 :     if (data == nullptr) {
    7875           0 :       return NullPointerError(cx, "read contents of", obj);
    7876             :     }
    7877           0 :     break;
    7878             :   case TYPE_array:
    7879           0 :     baseType = ArrayType::GetBaseType(typeObj);
    7880           0 :     data = CData::GetData(obj);
    7881           0 :     maxLength = ArrayType::GetLength(typeObj);
    7882           0 :     break;
    7883             :   default:
    7884           0 :     return TypeError(cx, "PointerType or ArrayType", args.thisv());
    7885             :   }
    7886             : 
    7887             :   // Convert the string buffer, taking care to determine the correct string
    7888             :   // length in the case of arrays (which may contain embedded nulls).
    7889             :   JSString* result;
    7890           0 :   switch (CType::GetTypeCode(baseType)) {
    7891             :   case TYPE_int8_t:
    7892             :   case TYPE_uint8_t:
    7893             :   case TYPE_char:
    7894             :   case TYPE_signed_char:
    7895             :   case TYPE_unsigned_char: {
    7896           0 :     char* bytes = static_cast<char*>(data);
    7897           0 :     size_t length = strnlen(bytes, maxLength);
    7898             : 
    7899             :     // Determine the length.
    7900           0 :     char16_t* dst = inflateUTF8(cx, JS::UTF8Chars(bytes, length), &length).get();
    7901           0 :     if (!dst)
    7902           0 :       return false;
    7903             : 
    7904           0 :     result = JS_NewUCString(cx, dst, length);
    7905           0 :     if (!result) {
    7906           0 :       js_free(dst);
    7907           0 :       return false;
    7908             :     }
    7909             : 
    7910           0 :     break;
    7911             :   }
    7912             :   case TYPE_int16_t:
    7913             :   case TYPE_uint16_t:
    7914             :   case TYPE_short:
    7915             :   case TYPE_unsigned_short:
    7916             :   case TYPE_char16_t: {
    7917           0 :     char16_t* chars = static_cast<char16_t*>(data);
    7918           0 :     size_t length = strnlen(chars, maxLength);
    7919           0 :     result = JS_NewUCStringCopyN(cx, chars, length);
    7920           0 :     break;
    7921             :   }
    7922             :   default:
    7923           0 :     return NonStringBaseError(cx, args.thisv());
    7924             :   }
    7925             : 
    7926           0 :   if (!result)
    7927           0 :     return false;
    7928             : 
    7929           0 :   args.rval().setString(result);
    7930           0 :   return true;
    7931             : }
    7932             : 
    7933             : bool
    7934           0 : CData::ReadString(JSContext* cx, unsigned argc, Value* vp)
    7935             : {
    7936             :   return ReadStringCommon(cx, JS::UTF8CharsToNewTwoByteCharsZ, argc, vp,
    7937           0 :                           "CData.prototype.readString");
    7938             : }
    7939             : 
    7940             : bool
    7941           0 : CDataFinalizer::Methods::ReadString(JSContext* cx, unsigned argc, Value* vp)
    7942             : {
    7943             :   return ReadStringCommon(cx, JS::UTF8CharsToNewTwoByteCharsZ, argc, vp,
    7944           0 :                           "CDataFinalizer.prototype.readString");
    7945             : }
    7946             : 
    7947             : bool
    7948           0 : CData::ReadStringReplaceMalformed(JSContext* cx, unsigned argc, Value* vp)
    7949             : {
    7950             :   return ReadStringCommon(cx, JS::LossyUTF8CharsToNewTwoByteCharsZ, argc, vp,
    7951           0 :                           "CData.prototype.readStringReplaceMalformed");
    7952             : }
    7953             : 
    7954             : JSString*
    7955           0 : CData::GetSourceString(JSContext* cx, HandleObject typeObj, void* data)
    7956             : {
    7957             :   // Walk the types, building up the toSource() string.
    7958             :   // First, we build up the type expression:
    7959             :   // 't.ptr' for pointers;
    7960             :   // 't.array([n])' for arrays;
    7961             :   // 'n' for structs, where n = t.name, the struct's name. (We assume this is
    7962             :   // bound to a variable in the current scope.)
    7963           0 :   AutoString source;
    7964           0 :   BuildTypeSource(cx, typeObj, true, source);
    7965           0 :   AppendString(source, "(");
    7966           0 :   if (!BuildDataSource(cx, typeObj, data, false, source))
    7967           0 :     return nullptr;
    7968             : 
    7969           0 :   AppendString(source, ")");
    7970             : 
    7971           0 :   return NewUCString(cx, source);
    7972             : }
    7973             : 
    7974             : bool
    7975           0 : CData::ToSource(JSContext* cx, unsigned argc, Value* vp)
    7976             : {
    7977           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    7978           0 :   if (args.length() != 0) {
    7979           0 :     return ArgumentLengthError(cx, "CData.prototype.toSource", "no", "s");
    7980             :   }
    7981             : 
    7982           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    7983           0 :   if (!obj)
    7984           0 :     return false;
    7985           0 :   if (!CData::IsCData(obj) && !CData::IsCDataProto(obj)) {
    7986           0 :     return IncompatibleThisProto(cx, "CData.prototype.toSource",
    7987           0 :                                  InformalValueTypeName(args.thisv()));
    7988             :   }
    7989             : 
    7990             :   JSString* result;
    7991           0 :   if (CData::IsCData(obj)) {
    7992           0 :     RootedObject typeObj(cx, CData::GetCType(obj));
    7993           0 :     void* data = CData::GetData(obj);
    7994             : 
    7995           0 :     result = CData::GetSourceString(cx, typeObj, data);
    7996             :   } else {
    7997           0 :     result = JS_NewStringCopyZ(cx, "[CData proto object]");
    7998             :   }
    7999             : 
    8000           0 :   if (!result)
    8001           0 :     return false;
    8002             : 
    8003           0 :   args.rval().setString(result);
    8004           0 :   return true;
    8005             : }
    8006             : 
    8007             : bool
    8008           0 : CData::ErrnoGetter(JSContext* cx, const JS::CallArgs& args)
    8009             : {
    8010           0 :   args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_ERRNO));
    8011           0 :   return true;
    8012             : }
    8013             : 
    8014             : #if defined(XP_WIN)
    8015             : bool
    8016             : CData::LastErrorGetter(JSContext* cx, const JS::CallArgs& args)
    8017             : {
    8018             :   args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), SLOT_LASTERROR));
    8019             :   return true;
    8020             : }
    8021             : #endif // defined(XP_WIN)
    8022             : 
    8023             : bool
    8024           0 : CDataFinalizer::Methods::ToSource(JSContext* cx, unsigned argc, Value* vp)
    8025             : {
    8026           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8027           0 :   RootedObject objThis(cx, JS_THIS_OBJECT(cx, vp));
    8028           0 :   if (!objThis)
    8029           0 :     return false;
    8030           0 :   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
    8031           0 :     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.toSource",
    8032           0 :                                  InformalValueTypeName(args.thisv()));
    8033             :   }
    8034             : 
    8035             :   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    8036           0 :     JS_GetPrivate(objThis);
    8037             : 
    8038             :   JSString* strMessage;
    8039           0 :   if (!p) {
    8040           0 :     strMessage = JS_NewStringCopyZ(cx, "ctypes.CDataFinalizer()");
    8041             :   } else {
    8042           0 :     RootedObject objType(cx, CDataFinalizer::GetCType(cx, objThis));
    8043           0 :     if (!objType) {
    8044           0 :       JS_ReportErrorASCII(cx, "CDataFinalizer has no type");
    8045           0 :       return false;
    8046             :     }
    8047             : 
    8048           0 :     AutoString source;
    8049           0 :     AppendString(source, "ctypes.CDataFinalizer(");
    8050           0 :     JSString* srcValue = CData::GetSourceString(cx, objType, p->cargs);
    8051           0 :     if (!srcValue) {
    8052           0 :       return false;
    8053             :     }
    8054           0 :     AppendString(source, srcValue);
    8055           0 :     AppendString(source, ", ");
    8056             :     Value valCodePtrType = JS_GetReservedSlot(objThis,
    8057           0 :                                               SLOT_DATAFINALIZER_CODETYPE);
    8058           0 :     if (valCodePtrType.isPrimitive()) {
    8059           0 :       return false;
    8060             :     }
    8061             : 
    8062           0 :     RootedObject typeObj(cx, valCodePtrType.toObjectOrNull());
    8063           0 :     JSString* srcDispose = CData::GetSourceString(cx, typeObj, &(p->code));
    8064           0 :     if (!srcDispose) {
    8065           0 :       return false;
    8066             :     }
    8067             : 
    8068           0 :     AppendString(source, srcDispose);
    8069           0 :     AppendString(source, ")");
    8070           0 :     strMessage = NewUCString(cx, source);
    8071             :   }
    8072             : 
    8073           0 :   if (!strMessage) {
    8074             :     // This is a memory issue, no error message
    8075           0 :     return false;
    8076             :   }
    8077             : 
    8078           0 :   args.rval().setString(strMessage);
    8079           0 :   return true;
    8080             : }
    8081             : 
    8082             : bool
    8083           0 : CDataFinalizer::Methods::ToString(JSContext* cx, unsigned argc, Value* vp)
    8084             : {
    8085           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8086           0 :   JSObject* objThis = JS_THIS_OBJECT(cx, vp);
    8087           0 :   if (!objThis)
    8088           0 :     return false;
    8089           0 :   if (!CDataFinalizer::IsCDataFinalizer(objThis)) {
    8090           0 :     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.toString",
    8091           0 :                                  InformalValueTypeName(args.thisv()));
    8092             :   }
    8093             : 
    8094             :   JSString* strMessage;
    8095           0 :   RootedValue value(cx);
    8096           0 :   if (!JS_GetPrivate(objThis)) {
    8097             :     // Pre-check whether CDataFinalizer::GetValue can fail
    8098             :     // to avoid reporting an error when not appropriate.
    8099           0 :     strMessage = JS_NewStringCopyZ(cx, "[CDataFinalizer - empty]");
    8100           0 :     if (!strMessage) {
    8101           0 :       return false;
    8102             :     }
    8103           0 :   } else if (!CDataFinalizer::GetValue(cx, objThis, &value)) {
    8104           0 :     MOZ_CRASH("Could not convert an empty CDataFinalizer");
    8105             :   } else {
    8106           0 :     strMessage = ToString(cx, value);
    8107           0 :     if (!strMessage) {
    8108           0 :       return false;
    8109             :     }
    8110             :   }
    8111           0 :   args.rval().setString(strMessage);
    8112           0 :   return true;
    8113             : }
    8114             : 
    8115             : bool
    8116           0 : CDataFinalizer::IsCDataFinalizer(JSObject* obj)
    8117             : {
    8118           0 :   return JS_GetClass(obj) == &sCDataFinalizerClass;
    8119             : }
    8120             : 
    8121             : 
    8122             : JSObject*
    8123           0 : CDataFinalizer::GetCType(JSContext* cx, JSObject* obj)
    8124             : {
    8125           0 :   MOZ_ASSERT(IsCDataFinalizer(obj));
    8126             : 
    8127             :   Value valData = JS_GetReservedSlot(obj,
    8128           0 :                                      SLOT_DATAFINALIZER_VALTYPE);
    8129           0 :   if (valData.isUndefined()) {
    8130           0 :     return nullptr;
    8131             :   }
    8132             : 
    8133           0 :   return valData.toObjectOrNull();
    8134             : }
    8135             : 
    8136             : bool
    8137           0 : CDataFinalizer::GetValue(JSContext* cx, JSObject* obj,
    8138             :                          MutableHandleValue aResult)
    8139             : {
    8140           0 :   MOZ_ASSERT(IsCDataFinalizer(obj));
    8141             : 
    8142             :   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    8143           0 :     JS_GetPrivate(obj);
    8144             : 
    8145           0 :   if (!p) {
    8146             :     // We have called |dispose| or |forget| already.
    8147           0 :     JS_ReportErrorASCII(cx, "Attempting to get the value of an empty CDataFinalizer");
    8148           0 :     return false;
    8149             :   }
    8150             : 
    8151           0 :   RootedObject ctype(cx, GetCType(cx, obj));
    8152           0 :   return ConvertToJS(cx, ctype, /*parent*/nullptr, p->cargs, false, true, aResult);
    8153             : }
    8154             : 
    8155             : /*
    8156             :  * Attach a C function as a finalizer to a JS object.
    8157             :  *
    8158             :  * Pseudo-JS signature:
    8159             :  * function(CData<T>, CData<T -> U>): CDataFinalizer<T>
    8160             :  *          value,    finalizer
    8161             :  *
    8162             :  * This function attaches strong references to the following values:
    8163             :  * - the CType of |value|
    8164             :  *
    8165             :  * Note: This function takes advantage of the fact that non-variadic
    8166             :  * CData functions are initialized during creation.
    8167             :  */
    8168             : bool
    8169           0 : CDataFinalizer::Construct(JSContext* cx, unsigned argc, Value* vp)
    8170             : {
    8171           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8172           0 :   RootedObject objSelf(cx, &args.callee());
    8173           0 :   RootedObject objProto(cx);
    8174           0 :   if (!GetObjectProperty(cx, objSelf, "prototype", &objProto)) {
    8175           0 :     JS_ReportErrorASCII(cx, "CDataFinalizer.prototype does not exist");
    8176           0 :     return false;
    8177             :   }
    8178             : 
    8179             :   // Get arguments
    8180           0 :   if (args.length() == 0) { // Special case: the empty (already finalized) object
    8181           0 :     JSObject* objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto);
    8182           0 :     args.rval().setObject(*objResult);
    8183           0 :     return true;
    8184             :   }
    8185             : 
    8186           0 :   if (args.length() != 2) {
    8187           0 :     return ArgumentLengthError(cx, "CDataFinalizer constructor", "two", "s");
    8188             :   }
    8189             : 
    8190           0 :   JS::HandleValue valCodePtr = args[1];
    8191           0 :   if (!valCodePtr.isObject()) {
    8192           0 :     return TypeError(cx, "_a CData object_ of a function pointer type",
    8193           0 :                      valCodePtr);
    8194             :   }
    8195           0 :   JSObject* objCodePtr = &valCodePtr.toObject();
    8196             : 
    8197             :   //Note: Using a custom argument formatter here would be awkward (requires
    8198             :   //a destructor just to uninstall the formatter).
    8199             : 
    8200             :   // 2. Extract argument type of |objCodePtr|
    8201           0 :   if (!CData::IsCData(objCodePtr)) {
    8202           0 :     return TypeError(cx, "a _CData_ object of a function pointer type",
    8203           0 :                      valCodePtr);
    8204             :   }
    8205           0 :   RootedObject objCodePtrType(cx, CData::GetCType(objCodePtr));
    8206           0 :   RootedValue valCodePtrType(cx, ObjectValue(*objCodePtrType));
    8207           0 :   MOZ_ASSERT(objCodePtrType);
    8208             : 
    8209           0 :   TypeCode typCodePtr = CType::GetTypeCode(objCodePtrType);
    8210           0 :   if (typCodePtr != TYPE_pointer) {
    8211           0 :     return TypeError(cx, "a CData object of a function _pointer_ type",
    8212           0 :                      valCodePtr);
    8213             :   }
    8214             : 
    8215           0 :   JSObject* objCodeType = PointerType::GetBaseType(objCodePtrType);
    8216           0 :   MOZ_ASSERT(objCodeType);
    8217             : 
    8218           0 :   TypeCode typCode = CType::GetTypeCode(objCodeType);
    8219           0 :   if (typCode != TYPE_function) {
    8220           0 :     return TypeError(cx, "a CData object of a _function_ pointer type",
    8221           0 :                      valCodePtr);
    8222             :   }
    8223           0 :   uintptr_t code = *reinterpret_cast<uintptr_t*>(CData::GetData(objCodePtr));
    8224           0 :   if (!code) {
    8225           0 :     return TypeError(cx, "a CData object of a _non-NULL_ function pointer type",
    8226           0 :                      valCodePtr);
    8227             :   }
    8228             : 
    8229             :   FunctionInfo* funInfoFinalizer =
    8230           0 :     FunctionType::GetFunctionInfo(objCodeType);
    8231           0 :   MOZ_ASSERT(funInfoFinalizer);
    8232             : 
    8233           0 :   if ((funInfoFinalizer->mArgTypes.length() != 1)
    8234           0 :       || (funInfoFinalizer->mIsVariadic)) {
    8235           0 :     RootedValue valCodeType(cx, ObjectValue(*objCodeType));
    8236           0 :     return TypeError(cx, "a function accepting exactly one argument",
    8237           0 :                      valCodeType);
    8238             :   }
    8239           0 :   RootedObject objArgType(cx, funInfoFinalizer->mArgTypes[0]);
    8240           0 :   RootedObject returnType(cx, funInfoFinalizer->mReturnType);
    8241             : 
    8242             :   // Invariant: At this stage, we know that funInfoFinalizer->mIsVariadic
    8243             :   // is |false|. Therefore, funInfoFinalizer->mCIF has already been initialized.
    8244             : 
    8245           0 :   bool freePointer = false;
    8246             : 
    8247             :   // 3. Perform dynamic cast of |args[0]| into |objType|, store it in |cargs|
    8248             : 
    8249             :   size_t sizeArg;
    8250           0 :   RootedValue valData(cx, args[0]);
    8251           0 :   if (!CType::GetSafeSize(objArgType, &sizeArg)) {
    8252           0 :     RootedValue valCodeType(cx, ObjectValue(*objCodeType));
    8253           0 :     return TypeError(cx, "a function with one known size argument",
    8254           0 :                      valCodeType);
    8255             :   }
    8256             : 
    8257           0 :   ScopedJSFreePtr<void> cargs(malloc(sizeArg));
    8258             : 
    8259           0 :   if (!ImplicitConvert(cx, valData, objArgType, cargs.get(),
    8260             :                        ConversionType::Finalizer, &freePointer,
    8261           0 :                        objCodePtrType, 0)) {
    8262           0 :     return false;
    8263             :   }
    8264           0 :   if (freePointer) {
    8265             :     // Note: We could handle that case, if necessary.
    8266           0 :     JS_ReportErrorASCII(cx, "Internal Error during CDataFinalizer. Object cannot be represented");
    8267           0 :     return false;
    8268             :   }
    8269             : 
    8270             :   // 4. Prepare buffer for holding return value
    8271             : 
    8272           0 :   ScopedJSFreePtr<void> rvalue;
    8273           0 :   if (CType::GetTypeCode(returnType) != TYPE_void_t) {
    8274           0 :     rvalue = malloc(Align(CType::GetSize(returnType),
    8275           0 :                           sizeof(ffi_arg)));
    8276             :   } //Otherwise, simply do not allocate
    8277             : 
    8278             :   // 5. Create |objResult|
    8279             : 
    8280           0 :   JSObject* objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto);
    8281           0 :   if (!objResult) {
    8282           0 :     return false;
    8283             :   }
    8284             : 
    8285             :   // If our argument is a CData, it holds a type.
    8286             :   // This is the type that we should capture, not that
    8287             :   // of the function, which may be less precise.
    8288           0 :   JSObject* objBestArgType = objArgType;
    8289           0 :   if (valData.isObject()) {
    8290           0 :     JSObject* objData = &valData.toObject();
    8291           0 :     if (CData::IsCData(objData)) {
    8292           0 :       objBestArgType = CData::GetCType(objData);
    8293             :       size_t sizeBestArg;
    8294           0 :       if (!CType::GetSafeSize(objBestArgType, &sizeBestArg)) {
    8295           0 :         MOZ_CRASH("object with unknown size");
    8296             :       }
    8297           0 :       if (sizeBestArg != sizeArg) {
    8298           0 :         return FinalizerSizeError(cx, objCodePtrType, valData);
    8299             :       }
    8300             :     }
    8301             :   }
    8302             : 
    8303             :   // Used by GetCType
    8304             :   JS_SetReservedSlot(objResult,
    8305             :                      SLOT_DATAFINALIZER_VALTYPE,
    8306           0 :                      ObjectOrNullValue(objBestArgType));
    8307             : 
    8308             :   // Used by ToSource
    8309             :   JS_SetReservedSlot(objResult,
    8310             :                      SLOT_DATAFINALIZER_CODETYPE,
    8311           0 :                      ObjectValue(*objCodePtrType));
    8312             : 
    8313           0 :   RootedValue abiType(cx, ObjectOrNullValue(funInfoFinalizer->mABI));
    8314             :   ffi_abi abi;
    8315           0 :   if (!GetABI(cx, abiType, &abi)) {
    8316             :     JS_ReportErrorASCII(cx, "Internal Error: "
    8317           0 :                         "Invalid ABI specification in CDataFinalizer");
    8318           0 :     return false;
    8319             :   }
    8320             : 
    8321           0 :   ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType);
    8322           0 :   if (!rtype) {
    8323             :     JS_ReportErrorASCII(cx, "Internal Error: "
    8324           0 :                         "Could not access ffi type of CDataFinalizer");
    8325           0 :     return false;
    8326             :   }
    8327             : 
    8328             :   // 7. Store C information as private
    8329             :   ScopedJSFreePtr<CDataFinalizer::Private>
    8330           0 :     p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private)));
    8331             : 
    8332           0 :   memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif));
    8333             : 
    8334           0 :   p->cargs = cargs.forget();
    8335           0 :   p->rvalue = rvalue.forget();
    8336           0 :   p->cargs_size = sizeArg;
    8337           0 :   p->code = code;
    8338             : 
    8339             : 
    8340           0 :   JS_SetPrivate(objResult, p.forget());
    8341           0 :   args.rval().setObject(*objResult);
    8342           0 :   return true;
    8343             : }
    8344             : 
    8345             : 
    8346             : /*
    8347             :  * Actually call the finalizer. Does not perform any cleanup on the object.
    8348             :  *
    8349             :  * Preconditions: |this| must be a |CDataFinalizer|, |p| must be non-null.
    8350             :  * The function fails if |this| has gone through |Forget|/|Dispose|
    8351             :  * or |Finalize|.
    8352             :  *
    8353             :  * This function does not alter the value of |errno|/|GetLastError|.
    8354             :  *
    8355             :  * If argument |errnoStatus| is non-nullptr, it receives the value of |errno|
    8356             :  * immediately after the call. Under Windows, if argument |lastErrorStatus|
    8357             :  * is non-nullptr, it receives the value of |GetLastError| immediately after
    8358             :  * the call. On other platforms, |lastErrorStatus| is ignored.
    8359             :  */
    8360             : void
    8361           0 : CDataFinalizer::CallFinalizer(CDataFinalizer::Private* p,
    8362             :                               int* errnoStatus,
    8363             :                               int32_t* lastErrorStatus)
    8364             : {
    8365           0 :   int savedErrno = errno;
    8366           0 :   errno = 0;
    8367             : #if defined(XP_WIN)
    8368             :   int32_t savedLastError = GetLastError();
    8369             :   SetLastError(0);
    8370             : #endif // defined(XP_WIN)
    8371             : 
    8372           0 :   void* args[1] = {p->cargs};
    8373           0 :   ffi_call(&p->CIF, FFI_FN(p->code), p->rvalue, args);
    8374             : 
    8375           0 :   if (errnoStatus) {
    8376           0 :     *errnoStatus = errno;
    8377             :   }
    8378           0 :   errno = savedErrno;
    8379             : #if defined(XP_WIN)
    8380             :   if (lastErrorStatus) {
    8381             :     *lastErrorStatus = GetLastError();
    8382             :   }
    8383             :   SetLastError(savedLastError);
    8384             : #endif // defined(XP_WIN)
    8385           0 : }
    8386             : 
    8387             : /*
    8388             :  * Forget the value.
    8389             :  *
    8390             :  * Preconditions: |this| must be a |CDataFinalizer|.
    8391             :  * The function fails if |this| has gone through |Forget|/|Dispose|
    8392             :  * or |Finalize|.
    8393             :  *
    8394             :  * Does not call the finalizer. Cleans up the Private memory and releases all
    8395             :  * strong references.
    8396             :  */
    8397             : bool
    8398           0 : CDataFinalizer::Methods::Forget(JSContext* cx, unsigned argc, Value* vp)
    8399             : {
    8400           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8401           0 :   if (args.length() != 0) {
    8402           0 :     return ArgumentLengthError(cx, "CDataFinalizer.prototype.forget", "no",
    8403           0 :                                "s");
    8404             :   }
    8405             : 
    8406           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    8407           0 :   if (!obj)
    8408           0 :     return false;
    8409           0 :   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
    8410           0 :     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.forget",
    8411           0 :                                  args.thisv());
    8412             :   }
    8413             : 
    8414             :   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    8415           0 :     JS_GetPrivate(obj);
    8416             : 
    8417           0 :   if (!p) {
    8418           0 :     return EmptyFinalizerCallError(cx, "CDataFinalizer.prototype.forget");
    8419             :   }
    8420             : 
    8421           0 :   RootedValue valJSData(cx);
    8422           0 :   RootedObject ctype(cx, GetCType(cx, obj));
    8423           0 :   if (!ConvertToJS(cx, ctype, nullptr, p->cargs, false, true, &valJSData)) {
    8424           0 :     JS_ReportErrorASCII(cx, "CDataFinalizer value cannot be represented");
    8425           0 :     return false;
    8426             :   }
    8427             : 
    8428           0 :   CDataFinalizer::Cleanup(p, obj);
    8429             : 
    8430           0 :   args.rval().set(valJSData);
    8431           0 :   return true;
    8432             : }
    8433             : 
    8434             : /*
    8435             :  * Clean up the value.
    8436             :  *
    8437             :  * Preconditions: |this| must be a |CDataFinalizer|.
    8438             :  * The function fails if |this| has gone through |Forget|/|Dispose|
    8439             :  * or |Finalize|.
    8440             :  *
    8441             :  * Calls the finalizer, cleans up the Private memory and releases all
    8442             :  * strong references.
    8443             :  */
    8444             : bool
    8445           0 : CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, Value* vp)
    8446             : {
    8447           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8448           0 :   if (args.length() != 0) {
    8449           0 :     return ArgumentLengthError(cx, "CDataFinalizer.prototype.dispose", "no",
    8450           0 :                                "s");
    8451             :   }
    8452             : 
    8453           0 :   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
    8454           0 :   if (!obj)
    8455           0 :     return false;
    8456           0 :   if (!CDataFinalizer::IsCDataFinalizer(obj)) {
    8457           0 :     return IncompatibleThisProto(cx, "CDataFinalizer.prototype.dispose",
    8458           0 :                                  args.thisv());
    8459             :   }
    8460             : 
    8461             :   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    8462           0 :     JS_GetPrivate(obj);
    8463             : 
    8464           0 :   if (!p) {
    8465           0 :     return EmptyFinalizerCallError(cx, "CDataFinalizer.prototype.dispose");
    8466             :   }
    8467             : 
    8468           0 :   Value valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE);
    8469           0 :   MOZ_ASSERT(valType.isObject());
    8470             : 
    8471           0 :   RootedObject objCTypes(cx, CType::GetGlobalCTypes(cx, &valType.toObject()));
    8472           0 :   if (!objCTypes)
    8473           0 :     return false;
    8474             : 
    8475           0 :   Value valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE);
    8476           0 :   MOZ_ASSERT(valCodePtrType.isObject());
    8477           0 :   JSObject* objCodePtrType = &valCodePtrType.toObject();
    8478             : 
    8479           0 :   JSObject* objCodeType = PointerType::GetBaseType(objCodePtrType);
    8480           0 :   MOZ_ASSERT(objCodeType);
    8481           0 :   MOZ_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function);
    8482             : 
    8483           0 :   RootedObject resultType(cx, FunctionType::GetFunctionInfo(objCodeType)->mReturnType);
    8484           0 :   RootedValue result(cx);
    8485             : 
    8486             :   int errnoStatus;
    8487             : #if defined(XP_WIN)
    8488             :   int32_t lastErrorStatus;
    8489             :   CDataFinalizer::CallFinalizer(p, &errnoStatus, &lastErrorStatus);
    8490             : #else
    8491           0 :   CDataFinalizer::CallFinalizer(p, &errnoStatus, nullptr);
    8492             : #endif // defined(XP_WIN)
    8493             : 
    8494           0 :   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, Int32Value(errnoStatus));
    8495             : #if defined(XP_WIN)
    8496             :   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, Int32Value(lastErrorStatus));
    8497             : #endif // defined(XP_WIN)
    8498             : 
    8499           0 :   if (ConvertToJS(cx, resultType, nullptr, p->rvalue, false, true, &result)) {
    8500           0 :     CDataFinalizer::Cleanup(p, obj);
    8501           0 :     args.rval().set(result);
    8502           0 :     return true;
    8503             :   }
    8504           0 :   CDataFinalizer::Cleanup(p, obj);
    8505           0 :   return false;
    8506             : }
    8507             : 
    8508             : /*
    8509             :  * Perform finalization.
    8510             :  *
    8511             :  * Preconditions: |this| must be the result of |CDataFinalizer|.
    8512             :  * It may have gone through |Forget|/|Dispose|.
    8513             :  *
    8514             :  * If |this| has not gone through |Forget|/|Dispose|, calls the
    8515             :  * finalizer, cleans up the Private memory and releases all
    8516             :  * strong references.
    8517             :  */
    8518             : void
    8519           0 : CDataFinalizer::Finalize(JSFreeOp* fop, JSObject* obj)
    8520             : {
    8521             :   CDataFinalizer::Private* p = (CDataFinalizer::Private*)
    8522           0 :     JS_GetPrivate(obj);
    8523             : 
    8524           0 :   if (!p) {
    8525           0 :     return;
    8526             :   }
    8527             : 
    8528           0 :   CDataFinalizer::CallFinalizer(p, nullptr, nullptr);
    8529           0 :   CDataFinalizer::Cleanup(p, nullptr);
    8530             : }
    8531             : 
    8532             : /*
    8533             :  * Perform cleanup of a CDataFinalizer
    8534             :  *
    8535             :  * Release strong references, cleanup |Private|.
    8536             :  *
    8537             :  * Argument |p| contains the private information of the CDataFinalizer. If
    8538             :  * nullptr, this function does nothing.
    8539             :  * Argument |obj| should contain |nullptr| during finalization (or in any
    8540             :  * context in which the object itself should not be cleaned up), or a
    8541             :  * CDataFinalizer object otherwise.
    8542             :  */
    8543             : void
    8544           0 : CDataFinalizer::Cleanup(CDataFinalizer::Private* p, JSObject* obj)
    8545             : {
    8546           0 :   if (!p) {
    8547           0 :     return;  // We have already cleaned up
    8548             :   }
    8549             : 
    8550           0 :   free(p->cargs);
    8551           0 :   free(p->rvalue);
    8552           0 :   free(p);
    8553             : 
    8554           0 :   if (!obj) {
    8555           0 :     return;  // No slots to clean up
    8556             :   }
    8557             : 
    8558           0 :   MOZ_ASSERT(CDataFinalizer::IsCDataFinalizer(obj));
    8559             : 
    8560           0 :   JS_SetPrivate(obj, nullptr);
    8561           0 :   for (int i = 0; i < CDATAFINALIZER_SLOTS; ++i) {
    8562           0 :     JS_SetReservedSlot(obj, i, JS::NullValue());
    8563             :   }
    8564             : }
    8565             : 
    8566             : 
    8567             : /*******************************************************************************
    8568             : ** Int64 and UInt64 implementation
    8569             : *******************************************************************************/
    8570             : 
    8571             : JSObject*
    8572           0 : Int64Base::Construct(JSContext* cx,
    8573             :                      HandleObject proto,
    8574             :                      uint64_t data,
    8575             :                      bool isUnsigned)
    8576             : {
    8577           0 :   const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
    8578           0 :   RootedObject result(cx, JS_NewObjectWithGivenProto(cx, clasp, proto));
    8579           0 :   if (!result)
    8580           0 :     return nullptr;
    8581             : 
    8582             :   // attach the Int64's data
    8583           0 :   uint64_t* buffer = cx->new_<uint64_t>(data);
    8584           0 :   if (!buffer) {
    8585           0 :     JS_ReportOutOfMemory(cx);
    8586           0 :     return nullptr;
    8587             :   }
    8588             : 
    8589           0 :   JS_SetReservedSlot(result, SLOT_INT64, PrivateValue(buffer));
    8590             : 
    8591           0 :   if (!JS_FreezeObject(cx, result))
    8592           0 :     return nullptr;
    8593             : 
    8594           0 :   return result;
    8595             : }
    8596             : 
    8597             : void
    8598           0 : Int64Base::Finalize(JSFreeOp* fop, JSObject* obj)
    8599             : {
    8600           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_INT64);
    8601           0 :   if (slot.isUndefined())
    8602           0 :     return;
    8603             : 
    8604           0 :   FreeOp::get(fop)->delete_(static_cast<uint64_t*>(slot.toPrivate()));
    8605             : }
    8606             : 
    8607             : uint64_t
    8608           0 : Int64Base::GetInt(JSObject* obj) {
    8609           0 :   MOZ_ASSERT(Int64::IsInt64(obj) || UInt64::IsUInt64(obj));
    8610             : 
    8611           0 :   Value slot = JS_GetReservedSlot(obj, SLOT_INT64);
    8612           0 :   return *static_cast<uint64_t*>(slot.toPrivate());
    8613             : }
    8614             : 
    8615             : bool
    8616           0 : Int64Base::ToString(JSContext* cx,
    8617             :                     JSObject* obj,
    8618             :                     const CallArgs& args,
    8619             :                     bool isUnsigned)
    8620             : {
    8621           0 :   if (args.length() > 1) {
    8622           0 :     if (isUnsigned) {
    8623             :       return ArgumentLengthError(cx, "UInt64.prototype.toString",
    8624           0 :                                  "at most one", "");
    8625             :     }
    8626             :     return ArgumentLengthError(cx, "Int64.prototype.toString",
    8627           0 :                                "at most one", "");
    8628             :   }
    8629             : 
    8630           0 :   int radix = 10;
    8631           0 :   if (args.length() == 1) {
    8632           0 :     Value arg = args[0];
    8633           0 :     if (arg.isInt32())
    8634           0 :       radix = arg.toInt32();
    8635           0 :     if (!arg.isInt32() || radix < 2 || radix > 36) {
    8636           0 :       if (isUnsigned) {
    8637           0 :         return ArgumentRangeMismatch(cx, "UInt64.prototype.toString", "an integer at least 2 and no greater than 36");
    8638             :       }
    8639           0 :       return ArgumentRangeMismatch(cx, "Int64.prototype.toString", "an integer at least 2 and no greater than 36");
    8640             :     }
    8641             :   }
    8642             : 
    8643           0 :   AutoString intString;
    8644           0 :   if (isUnsigned) {
    8645           0 :     IntegerToString(GetInt(obj), radix, intString);
    8646             :   } else {
    8647           0 :     IntegerToString(static_cast<int64_t>(GetInt(obj)), radix, intString);
    8648             :   }
    8649             : 
    8650           0 :   JSString* result = NewUCString(cx, intString);
    8651           0 :   if (!result)
    8652           0 :     return false;
    8653             : 
    8654           0 :   args.rval().setString(result);
    8655           0 :   return true;
    8656             : }
    8657             : 
    8658             : bool
    8659           0 : Int64Base::ToSource(JSContext* cx,
    8660             :                     JSObject* obj,
    8661             :                     const CallArgs& args,
    8662             :                     bool isUnsigned)
    8663             : {
    8664           0 :   if (args.length() != 0) {
    8665           0 :     if (isUnsigned) {
    8666           0 :       return ArgumentLengthError(cx, "UInt64.prototype.toSource", "no", "s");
    8667             :     }
    8668           0 :     return ArgumentLengthError(cx, "Int64.prototype.toSource", "no", "s");
    8669             :   }
    8670             : 
    8671             :   // Return a decimal string suitable for constructing the number.
    8672           0 :   AutoString source;
    8673           0 :   if (isUnsigned) {
    8674           0 :     AppendString(source, "ctypes.UInt64(\"");
    8675           0 :     IntegerToString(GetInt(obj), 10, source);
    8676             :   } else {
    8677           0 :     AppendString(source, "ctypes.Int64(\"");
    8678           0 :     IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
    8679             :   }
    8680           0 :   AppendString(source, "\")");
    8681             : 
    8682           0 :   JSString* result = NewUCString(cx, source);
    8683           0 :   if (!result)
    8684           0 :     return false;
    8685             : 
    8686           0 :   args.rval().setString(result);
    8687           0 :   return true;
    8688             : }
    8689             : 
    8690             : bool
    8691           0 : Int64::Construct(JSContext* cx,
    8692             :                  unsigned argc,
    8693             :                  Value* vp)
    8694             : {
    8695           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8696             : 
    8697             :   // Construct and return a new Int64 object.
    8698           0 :   if (args.length() != 1) {
    8699           0 :     return ArgumentLengthError(cx, "Int64 constructor", "one", "");
    8700             :   }
    8701             : 
    8702           0 :   int64_t i = 0;
    8703           0 :   bool overflow = false;
    8704           0 :   if (!jsvalToBigInteger(cx, args[0], true, &i, &overflow)) {
    8705           0 :     if (overflow) {
    8706           0 :       return TypeOverflow(cx, "int64", args[0]);
    8707             :     }
    8708           0 :     return ArgumentConvError(cx, args[0], "Int64", 0);
    8709             :   }
    8710             : 
    8711             :   // Get ctypes.Int64.prototype from the 'prototype' property of the ctor.
    8712           0 :   RootedValue slot(cx);
    8713           0 :   RootedObject callee(cx, &args.callee());
    8714           0 :   ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
    8715           0 :   RootedObject proto(cx, slot.toObjectOrNull());
    8716           0 :   MOZ_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
    8717             : 
    8718           0 :   JSObject* result = Int64Base::Construct(cx, proto, i, false);
    8719           0 :   if (!result)
    8720           0 :     return false;
    8721             : 
    8722           0 :   args.rval().setObject(*result);
    8723           0 :   return true;
    8724             : }
    8725             : 
    8726             : bool
    8727           0 : Int64::IsInt64(JSObject* obj)
    8728             : {
    8729           0 :   return JS_GetClass(obj) == &sInt64Class;
    8730             : }
    8731             : 
    8732             : bool
    8733           0 : Int64::ToString(JSContext* cx, unsigned argc, Value* vp)
    8734             : {
    8735           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8736           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    8737           0 :   if (!obj)
    8738           0 :     return false;
    8739           0 :   if (!Int64::IsInt64(obj)) {
    8740           0 :     if (!CData::IsCData(obj)) {
    8741           0 :       return IncompatibleThisProto(cx, "Int64.prototype.toString",
    8742           0 :                                    InformalValueTypeName(args.thisv()));
    8743             :     }
    8744             :     return IncompatibleThisType(cx, "Int64.prototype.toString",
    8745           0 :                                 "non-Int64 CData");
    8746             :   }
    8747             : 
    8748           0 :   return Int64Base::ToString(cx, obj, args, false);
    8749             : }
    8750             : 
    8751             : bool
    8752           0 : Int64::ToSource(JSContext* cx, unsigned argc, Value* vp)
    8753             : {
    8754           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8755           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    8756           0 :   if (!obj)
    8757           0 :     return false;
    8758           0 :   if (!Int64::IsInt64(obj)) {
    8759           0 :     if (!CData::IsCData(obj)) {
    8760           0 :       return IncompatibleThisProto(cx, "Int64.prototype.toSource",
    8761           0 :                                    InformalValueTypeName(args.thisv()));
    8762             :     }
    8763             :     return IncompatibleThisType(cx, "Int64.prototype.toSource",
    8764           0 :                                 "non-Int64 CData");
    8765             :   }
    8766             : 
    8767           0 :   return Int64Base::ToSource(cx, obj, args, false);
    8768             : }
    8769             : 
    8770             : bool
    8771           0 : Int64::Compare(JSContext* cx, unsigned argc, Value* vp)
    8772             : {
    8773           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8774           0 :   if (args.length() != 2) {
    8775           0 :     return ArgumentLengthError(cx, "Int64.compare", "two", "s");
    8776             :   }
    8777           0 :   if (args[0].isPrimitive() || !Int64::IsInt64(&args[0].toObject())) {
    8778           0 :     return ArgumentTypeMismatch(cx, "first ", "Int64.compare", "a Int64");
    8779             :   }
    8780           0 :   if (args[1].isPrimitive() ||!Int64::IsInt64(&args[1].toObject())) {
    8781           0 :     return ArgumentTypeMismatch(cx, "second ", "Int64.compare", "a Int64");
    8782             :   }
    8783             : 
    8784           0 :   JSObject* obj1 = &args[0].toObject();
    8785           0 :   JSObject* obj2 = &args[1].toObject();
    8786             : 
    8787           0 :   int64_t i1 = Int64Base::GetInt(obj1);
    8788           0 :   int64_t i2 = Int64Base::GetInt(obj2);
    8789             : 
    8790           0 :   if (i1 == i2)
    8791           0 :     args.rval().setInt32(0);
    8792           0 :   else if (i1 < i2)
    8793           0 :     args.rval().setInt32(-1);
    8794             :   else
    8795           0 :     args.rval().setInt32(1);
    8796             : 
    8797           0 :   return true;
    8798             : }
    8799             : 
    8800             : #define LO_MASK ((uint64_t(1) << 32) - 1)
    8801             : #define INT64_LO(i) ((i) & LO_MASK)
    8802             : #define INT64_HI(i) ((i) >> 32)
    8803             : 
    8804             : bool
    8805           0 : Int64::Lo(JSContext* cx, unsigned argc, Value* vp)
    8806             : {
    8807           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8808           0 :   if (args.length() != 1) {
    8809           0 :     return ArgumentLengthError(cx, "Int64.lo", "one", "");
    8810             :   }
    8811           0 :   if (args[0].isPrimitive() || !Int64::IsInt64(&args[0].toObject())) {
    8812           0 :     return ArgumentTypeMismatch(cx, "", "Int64.lo", "a Int64");
    8813             :   }
    8814             : 
    8815           0 :   JSObject* obj = &args[0].toObject();
    8816           0 :   int64_t u = Int64Base::GetInt(obj);
    8817           0 :   double d = uint32_t(INT64_LO(u));
    8818             : 
    8819           0 :   args.rval().setNumber(d);
    8820           0 :   return true;
    8821             : }
    8822             : 
    8823             : bool
    8824           0 : Int64::Hi(JSContext* cx, unsigned argc, Value* vp)
    8825             : {
    8826           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8827           0 :   if (args.length() != 1) {
    8828           0 :     return ArgumentLengthError(cx, "Int64.hi", "one", "");
    8829             :   }
    8830           0 :   if (args[0].isPrimitive() || !Int64::IsInt64(&args[0].toObject())) {
    8831           0 :     return ArgumentTypeMismatch(cx, "", "Int64.hi", "a Int64");
    8832             :   }
    8833             : 
    8834           0 :   JSObject* obj = &args[0].toObject();
    8835           0 :   int64_t u = Int64Base::GetInt(obj);
    8836           0 :   double d = int32_t(INT64_HI(u));
    8837             : 
    8838           0 :   args.rval().setDouble(d);
    8839           0 :   return true;
    8840             : }
    8841             : 
    8842             : bool
    8843           0 : Int64::Join(JSContext* cx, unsigned argc, Value* vp)
    8844             : {
    8845           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8846           0 :   if (args.length() != 2) {
    8847           0 :     return ArgumentLengthError(cx, "Int64.join", "two", "s");
    8848             :   }
    8849             : 
    8850             :   int32_t hi;
    8851             :   uint32_t lo;
    8852           0 :   if (!jsvalToInteger(cx, args[0], &hi))
    8853           0 :     return ArgumentConvError(cx, args[0], "Int64.join", 0);
    8854           0 :   if (!jsvalToInteger(cx, args[1], &lo))
    8855           0 :     return ArgumentConvError(cx, args[1], "Int64.join", 1);
    8856             : 
    8857           0 :   int64_t i = (int64_t(hi) << 32) + int64_t(lo);
    8858             : 
    8859             :   // Get Int64.prototype from the function's reserved slot.
    8860           0 :   JSObject* callee = &args.callee();
    8861             : 
    8862           0 :   Value slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
    8863           0 :   RootedObject proto(cx, &slot.toObject());
    8864           0 :   MOZ_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
    8865             : 
    8866           0 :   JSObject* result = Int64Base::Construct(cx, proto, i, false);
    8867           0 :   if (!result)
    8868           0 :     return false;
    8869             : 
    8870           0 :   args.rval().setObject(*result);
    8871           0 :   return true;
    8872             : }
    8873             : 
    8874             : bool
    8875           0 : UInt64::Construct(JSContext* cx,
    8876             :                   unsigned argc,
    8877             :                   Value* vp)
    8878             : {
    8879           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8880             : 
    8881             :   // Construct and return a new UInt64 object.
    8882           0 :   if (args.length() != 1) {
    8883           0 :     return ArgumentLengthError(cx, "UInt64 constructor", "one", "");
    8884             :   }
    8885             : 
    8886           0 :   uint64_t u = 0;
    8887           0 :   bool overflow = false;
    8888           0 :   if (!jsvalToBigInteger(cx, args[0], true, &u, &overflow)) {
    8889           0 :     if (overflow) {
    8890           0 :       return TypeOverflow(cx, "uint64", args[0]);
    8891             :     }
    8892           0 :     return ArgumentConvError(cx, args[0], "UInt64", 0);
    8893             :   }
    8894             : 
    8895             :   // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor.
    8896           0 :   RootedValue slot(cx);
    8897           0 :   RootedObject callee(cx, &args.callee());
    8898           0 :   ASSERT_OK(JS_GetProperty(cx, callee, "prototype", &slot));
    8899           0 :   RootedObject proto(cx, &slot.toObject());
    8900           0 :   MOZ_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
    8901             : 
    8902           0 :   JSObject* result = Int64Base::Construct(cx, proto, u, true);
    8903           0 :   if (!result)
    8904           0 :     return false;
    8905             : 
    8906           0 :   args.rval().setObject(*result);
    8907           0 :   return true;
    8908             : }
    8909             : 
    8910             : bool
    8911           0 : UInt64::IsUInt64(JSObject* obj)
    8912             : {
    8913           0 :   return JS_GetClass(obj) == &sUInt64Class;
    8914             : }
    8915             : 
    8916             : bool
    8917           0 : UInt64::ToString(JSContext* cx, unsigned argc, Value* vp)
    8918             : {
    8919           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8920           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    8921           0 :   if (!obj)
    8922           0 :     return false;
    8923           0 :   if (!UInt64::IsUInt64(obj)) {
    8924           0 :     if (!CData::IsCData(obj)) {
    8925           0 :       return IncompatibleThisProto(cx, "UInt64.prototype.toString",
    8926           0 :                                    InformalValueTypeName(args.thisv()));
    8927             :     }
    8928             :     return IncompatibleThisType(cx, "UInt64.prototype.toString",
    8929           0 :                                 "non-UInt64 CData");
    8930             :   }
    8931             : 
    8932           0 :   return Int64Base::ToString(cx, obj, args, true);
    8933             : }
    8934             : 
    8935             : bool
    8936           0 : UInt64::ToSource(JSContext* cx, unsigned argc, Value* vp)
    8937             : {
    8938           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8939           0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    8940           0 :   if (!obj)
    8941           0 :     return false;
    8942           0 :   if (!UInt64::IsUInt64(obj)) {
    8943           0 :     if (!CData::IsCData(obj)) {
    8944           0 :       return IncompatibleThisProto(cx, "UInt64.prototype.toSource",
    8945           0 :                                    InformalValueTypeName(args.thisv()));
    8946             :     }
    8947             :     return IncompatibleThisType(cx, "UInt64.prototype.toSource",
    8948           0 :                                 "non-UInt64 CData");
    8949             :   }
    8950             : 
    8951           0 :   return Int64Base::ToSource(cx, obj, args, true);
    8952             : }
    8953             : 
    8954             : bool
    8955           0 : UInt64::Compare(JSContext* cx, unsigned argc, Value* vp)
    8956             : {
    8957           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8958           0 :   if (args.length() != 2) {
    8959           0 :     return ArgumentLengthError(cx, "UInt64.compare", "two", "s");
    8960             :   }
    8961           0 :   if (args[0].isPrimitive() || !UInt64::IsUInt64(&args[0].toObject())) {
    8962           0 :     return ArgumentTypeMismatch(cx, "first ", "UInt64.compare", "a UInt64");
    8963             :   }
    8964           0 :   if (args[1].isPrimitive() || !UInt64::IsUInt64(&args[1].toObject())) {
    8965           0 :     return ArgumentTypeMismatch(cx, "second ", "UInt64.compare", "a UInt64");
    8966             :   }
    8967             : 
    8968           0 :   JSObject* obj1 = &args[0].toObject();
    8969           0 :   JSObject* obj2 = &args[1].toObject();
    8970             : 
    8971           0 :   uint64_t u1 = Int64Base::GetInt(obj1);
    8972           0 :   uint64_t u2 = Int64Base::GetInt(obj2);
    8973             : 
    8974           0 :   if (u1 == u2)
    8975           0 :     args.rval().setInt32(0);
    8976           0 :   else if (u1 < u2)
    8977           0 :     args.rval().setInt32(-1);
    8978             :   else
    8979           0 :     args.rval().setInt32(1);
    8980             : 
    8981           0 :   return true;
    8982             : }
    8983             : 
    8984             : bool
    8985           0 : UInt64::Lo(JSContext* cx, unsigned argc, Value* vp)
    8986             : {
    8987           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    8988           0 :   if (args.length() != 1) {
    8989           0 :     return ArgumentLengthError(cx, "UInt64.lo", "one", "");
    8990             :   }
    8991           0 :   if (args[0].isPrimitive() || !UInt64::IsUInt64(&args[0].toObject())) {
    8992           0 :     return ArgumentTypeMismatch(cx, "", "UInt64.lo", "a UInt64");
    8993             :   }
    8994             : 
    8995           0 :   JSObject* obj = &args[0].toObject();
    8996           0 :   uint64_t u = Int64Base::GetInt(obj);
    8997           0 :   double d = uint32_t(INT64_LO(u));
    8998             : 
    8999           0 :   args.rval().setDouble(d);
    9000           0 :   return true;
    9001             : }
    9002             : 
    9003             : bool
    9004           0 : UInt64::Hi(JSContext* cx, unsigned argc, Value* vp)
    9005             : {
    9006           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    9007           0 :   if (args.length() != 1) {
    9008           0 :     return ArgumentLengthError(cx, "UInt64.hi", "one", "");
    9009             :   }
    9010           0 :   if (args[0].isPrimitive() || !UInt64::IsUInt64(&args[0].toObject())) {
    9011           0 :     return ArgumentTypeMismatch(cx, "", "UInt64.hi", "a UInt64");
    9012             :   }
    9013             : 
    9014           0 :   JSObject* obj = &args[0].toObject();
    9015           0 :   uint64_t u = Int64Base::GetInt(obj);
    9016           0 :   double d = uint32_t(INT64_HI(u));
    9017             : 
    9018           0 :   args.rval().setDouble(d);
    9019           0 :   return true;
    9020             : }
    9021             : 
    9022             : bool
    9023           0 : UInt64::Join(JSContext* cx, unsigned argc, Value* vp)
    9024             : {
    9025           0 :   CallArgs args = CallArgsFromVp(argc, vp);
    9026           0 :   if (args.length() != 2) {
    9027           0 :     return ArgumentLengthError(cx, "UInt64.join", "two", "s");
    9028             :   }
    9029             : 
    9030             :   uint32_t hi;
    9031             :   uint32_t lo;
    9032           0 :   if (!jsvalToInteger(cx, args[0], &hi))
    9033           0 :     return ArgumentConvError(cx, args[0], "UInt64.join", 0);
    9034           0 :   if (!jsvalToInteger(cx, args[1], &lo))
    9035           0 :     return ArgumentConvError(cx, args[1], "UInt64.join", 1);
    9036             : 
    9037           0 :   uint64_t u = (uint64_t(hi) << 32) + uint64_t(lo);
    9038             : 
    9039             :   // Get UInt64.prototype from the function's reserved slot.
    9040           0 :   JSObject* callee = &args.callee();
    9041             : 
    9042           0 :   Value slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
    9043           0 :   RootedObject proto(cx, &slot.toObject());
    9044           0 :   MOZ_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
    9045             : 
    9046           0 :   JSObject* result = Int64Base::Construct(cx, proto, u, true);
    9047           0 :   if (!result)
    9048           0 :     return false;
    9049             : 
    9050           0 :   args.rval().setObject(*result);
    9051           0 :   return true;
    9052             : }
    9053             : 
    9054             : } // namespace ctypes
    9055             : } // namespace js

Generated by: LCOV version 1.13