LCOV - code coverage report
Current view: directory - js/src/ctypes - CTypes.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2770 219 7.9 %
Date: 2012-04-07 Functions: 549 21 3.8 %

       1                 : /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is js-ctypes.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * The Mozilla Foundation <http://www.mozilla.org/>.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Dan Witte <dwitte@mozilla.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "CTypes.h"
      40                 : #include "Library.h"
      41                 : #include "jsnum.h"
      42                 : #include "jscompartment.h"
      43                 : #include "jsobjinlines.h"
      44                 : #include <limits>
      45                 : 
      46                 : #include <math.h>
      47                 : #if defined(XP_WIN) || defined(XP_OS2)
      48                 : #include <float.h>
      49                 : #endif
      50                 : 
      51                 : #if defined(SOLARIS)
      52                 : #include <ieeefp.h>
      53                 : #endif
      54                 : 
      55                 : #ifdef HAVE_SSIZE_T
      56                 : #include <sys/types.h>
      57                 : #endif
      58                 : 
      59                 : #if defined(XP_UNIX)
      60                 : #include <errno.h>
      61                 : #elif defined(XP_WIN)
      62                 : #include <windows.h>
      63                 : #endif
      64                 : 
      65                 : using namespace std;
      66                 : 
      67                 : namespace js {
      68                 : namespace ctypes {
      69                 : 
      70                 : /*******************************************************************************
      71                 : ** JSAPI function prototypes
      72                 : *******************************************************************************/
      73                 : 
      74                 : static JSBool ConstructAbstract(JSContext* cx, unsigned argc, jsval* vp);
      75                 : 
      76                 : namespace CType {
      77                 :   static JSBool ConstructData(JSContext* cx, unsigned argc, jsval* vp);
      78                 :   static JSBool ConstructBasic(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp);
      79                 : 
      80                 :   static void Trace(JSTracer* trc, JSObject* obj);
      81                 :   static void Finalize(JSFreeOp *fop, JSObject* obj);
      82                 :   static void FinalizeProtoClass(JSFreeOp *fop, JSObject* obj);
      83                 : 
      84                 :   static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval,
      85                 :     jsval* vp);
      86                 :   static JSBool NameGetter(JSContext* cx, JSObject* obj, jsid idval,
      87                 :     jsval* vp);
      88                 :   static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsid idval,
      89                 :     jsval* vp);
      90                 :   static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp);
      91                 :   static JSBool CreateArray(JSContext* cx, unsigned argc, jsval* vp);
      92                 :   static JSBool ToString(JSContext* cx, unsigned argc, jsval* vp);
      93                 :   static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp);
      94                 :   static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp);
      95                 : 
      96                 : 
      97                 :   /**
      98                 :    * Get the global "ctypes" object.
      99                 :    *
     100                 :    * |obj| must be a CType object.
     101                 :    *
     102                 :    * This function never returns NULL.
     103                 :    */
     104                 :   static JSObject* GetGlobalCTypes(JSContext* cx, JSObject* obj);
     105                 : 
     106                 : }
     107                 : 
     108                 : namespace PointerType {
     109                 :   static JSBool Create(JSContext* cx, unsigned argc, jsval* vp);
     110                 :   static JSBool ConstructData(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp);
     111                 : 
     112                 :   static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsid idval,
     113                 :     jsval* vp);
     114                 :   static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsid idval,
     115                 :     jsval* vp);
     116                 :   static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict,
     117                 :     jsval* vp);
     118                 :   static JSBool IsNull(JSContext* cx, unsigned argc, jsval* vp);
     119                 :   static JSBool Increment(JSContext* cx, unsigned argc, jsval* vp);
     120                 :   static JSBool Decrement(JSContext* cx, unsigned argc, jsval* vp);
     121                 :   // The following is not an instance function, since we don't want to expose arbitrary
     122                 :   // pointer arithmetic at this moment.
     123                 :   static JSBool OffsetBy(JSContext* cx, int offset, jsval* vp);
     124                 : }
     125                 : 
     126                 : namespace ArrayType {
     127                 :   static JSBool Create(JSContext* cx, unsigned argc, jsval* vp);
     128                 :   static JSBool ConstructData(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp);
     129                 : 
     130                 :   static JSBool ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval,
     131                 :     jsval* vp);
     132                 :   static JSBool LengthGetter(JSContext* cx, JSObject* obj, jsid idval,
     133                 :     jsval* vp);
     134                 :   static JSBool Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp);
     135                 :   static JSBool Setter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp);
     136                 :   static JSBool AddressOfElement(JSContext* cx, unsigned argc, jsval* vp);
     137                 : }
     138                 : 
     139                 : namespace StructType {
     140                 :   static JSBool Create(JSContext* cx, unsigned argc, jsval* vp);
     141                 :   static JSBool ConstructData(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp);
     142                 : 
     143                 :   static JSBool FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval,
     144                 :     jsval* vp);
     145                 :   static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsid idval,
     146                 :     jsval* vp);
     147                 :   static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict,
     148                 :                             jsval* vp);
     149                 :   static JSBool AddressOfField(JSContext* cx, unsigned argc, jsval* vp);
     150                 :   static JSBool Define(JSContext* cx, unsigned argc, jsval* vp);
     151                 : }
     152                 : 
     153                 : namespace FunctionType {
     154                 :   static JSBool Create(JSContext* cx, unsigned argc, jsval* vp);
     155                 :   static JSBool ConstructData(JSContext* cx, JSObject* typeObj,
     156                 :     JSObject* dataObj, JSObject* fnObj, JSObject* thisObj, jsval errVal);
     157                 : 
     158                 :   static JSBool Call(JSContext* cx, unsigned argc, jsval* vp);
     159                 : 
     160                 :   static JSBool ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval,
     161                 :     jsval* vp);
     162                 :   static JSBool ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval,
     163                 :     jsval* vp);
     164                 :   static JSBool ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp);
     165                 :   static JSBool IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval,
     166                 :     jsval* vp);
     167                 : }
     168                 : 
     169                 : namespace CClosure {
     170                 :   static void Trace(JSTracer* trc, JSObject* obj);
     171                 :   static void Finalize(JSFreeOp *fop, JSObject* obj);
     172                 : 
     173                 :   // libffi callback
     174                 :   static void ClosureStub(ffi_cif* cif, void* result, void** args,
     175                 :     void* userData);
     176                 : }
     177                 : 
     178                 : namespace CData {
     179                 :   static void Finalize(JSFreeOp *fop, JSObject* obj);
     180                 : 
     181                 :   static JSBool ValueGetter(JSContext* cx, JSObject* obj, jsid idval,
     182                 :                             jsval* vp);
     183                 :   static JSBool ValueSetter(JSContext* cx, JSObject* obj, jsid idval,
     184                 :                             JSBool strict, jsval* vp);
     185                 :   static JSBool Address(JSContext* cx, unsigned argc, jsval* vp);
     186                 :   static JSBool ReadString(JSContext* cx, unsigned argc, jsval* vp);
     187                 :   static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp);
     188                 : 
     189                 :   static JSBool ErrnoGetter(JSContext* cx, JSObject *obj, jsid idval,
     190                 :                             jsval* vp);
     191                 : 
     192                 : #if defined(XP_WIN)
     193                 :   static JSBool LastErrorGetter(JSContext* cx, JSObject *obj, jsid idval,
     194                 :                                 jsval* vp);
     195                 : #endif // defined(XP_WIN)
     196                 : }
     197                 : 
     198                 : // Int64Base provides functions common to Int64 and UInt64.
     199                 : namespace Int64Base {
     200                 :   JSObject* Construct(JSContext* cx, JSObject* proto, uint64_t data,
     201                 :     bool isUnsigned);
     202                 : 
     203                 :   uint64_t GetInt(JSObject* obj);
     204                 : 
     205                 :   JSBool ToString(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp,
     206                 :     bool isUnsigned);
     207                 : 
     208                 :   JSBool ToSource(JSContext* cx, JSObject* obj, unsigned argc, jsval* vp,
     209                 :     bool isUnsigned);
     210                 : 
     211                 :   static void Finalize(JSFreeOp *fop, JSObject* obj);
     212                 : }
     213                 : 
     214                 : namespace Int64 {
     215                 :   static JSBool Construct(JSContext* cx, unsigned argc, jsval* vp);
     216                 : 
     217                 :   static JSBool ToString(JSContext* cx, unsigned argc, jsval* vp);
     218                 :   static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp);
     219                 : 
     220                 :   static JSBool Compare(JSContext* cx, unsigned argc, jsval* vp);
     221                 :   static JSBool Lo(JSContext* cx, unsigned argc, jsval* vp);
     222                 :   static JSBool Hi(JSContext* cx, unsigned argc, jsval* vp);
     223                 :   static JSBool Join(JSContext* cx, unsigned argc, jsval* vp);
     224                 : }
     225                 : 
     226                 : namespace UInt64 {
     227                 :   static JSBool Construct(JSContext* cx, unsigned argc, jsval* vp);
     228                 : 
     229                 :   static JSBool ToString(JSContext* cx, unsigned argc, jsval* vp);
     230                 :   static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp);
     231                 : 
     232                 :   static JSBool Compare(JSContext* cx, unsigned argc, jsval* vp);
     233                 :   static JSBool Lo(JSContext* cx, unsigned argc, jsval* vp);
     234                 :   static JSBool Hi(JSContext* cx, unsigned argc, jsval* vp);
     235                 :   static JSBool Join(JSContext* cx, unsigned argc, jsval* vp);
     236                 : }
     237                 : 
     238                 : /*******************************************************************************
     239                 : ** JSClass definitions and initialization functions
     240                 : *******************************************************************************/
     241                 : 
     242                 : // Class representing the 'ctypes' object itself. This exists to contain the
     243                 : // JSCTypesCallbacks set of function pointers.
     244                 : static JSClass sCTypesGlobalClass = {
     245                 :   "ctypes",
     246                 :   JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS),
     247                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     248                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
     249                 : };
     250                 : 
     251                 : static JSClass sCABIClass = {
     252                 :   "CABI",
     253                 :   JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS),
     254                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     255                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
     256                 : };
     257                 : 
     258                 : // Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype.
     259                 : // This exists to give said prototypes a class of "CType", and to provide
     260                 : // reserved slots for stashing various other prototype objects.
     261                 : static JSClass sCTypeProtoClass = {
     262                 :   "CType",
     263                 :   JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS),
     264                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     265                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::FinalizeProtoClass,
     266                 :   NULL, ConstructAbstract, ConstructAbstract
     267                 : };
     268                 : 
     269                 : // Class representing ctypes.CData.prototype and the 'prototype' properties
     270                 : // of CTypes. This exists to give said prototypes a class of "CData".
     271                 : static JSClass sCDataProtoClass = {
     272                 :   "CData",
     273                 :   0,
     274                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     275                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
     276                 : };
     277                 : 
     278                 : static JSClass sCTypeClass = {
     279                 :   "CType",
     280                 :   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
     281                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     282                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize,
     283                 :   NULL, CType::ConstructData, CType::ConstructData,
     284                 :   CType::HasInstance, CType::Trace
     285                 : };
     286                 : 
     287                 : static JSClass sCDataClass = {
     288                 :   "CData",
     289                 :   JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS),
     290                 :   JS_PropertyStub, JS_PropertyStub, ArrayType::Getter, ArrayType::Setter,
     291                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize,
     292                 :   NULL, FunctionType::Call, FunctionType::Call
     293                 : };
     294                 : 
     295                 : static JSClass sCClosureClass = {
     296                 :   "CClosure",
     297                 :   JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
     298                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     299                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize,
     300                 :   NULL, NULL, NULL, NULL, CClosure::Trace
     301                 : };
     302                 : 
     303                 : #define CTYPESFN_FLAGS \
     304                 :   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
     305                 : 
     306                 : #define CTYPESCTOR_FLAGS \
     307                 :   (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR)
     308                 : 
     309                 : #define CTYPESPROP_FLAGS \
     310                 :   (JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
     311                 : 
     312                 : #define CDATAFN_FLAGS \
     313                 :   (JSPROP_READONLY | JSPROP_PERMANENT)
     314                 : 
     315                 : static JSPropertySpec sCTypeProps[] = {
     316                 :   { "name", 0, CTYPESPROP_FLAGS, CType::NameGetter, NULL },
     317                 :   { "size", 0, CTYPESPROP_FLAGS, CType::SizeGetter, NULL },
     318                 :   { "ptr", 0, CTYPESPROP_FLAGS, CType::PtrGetter, NULL },
     319                 :   { "prototype", 0, CTYPESPROP_FLAGS, CType::PrototypeGetter, NULL },
     320                 :   { 0, 0, 0, NULL, NULL }
     321                 : };
     322                 : 
     323                 : static JSFunctionSpec sCTypeFunctions[] = {
     324                 :   JS_FN("array", CType::CreateArray, 0, CTYPESFN_FLAGS),
     325                 :   JS_FN("toString", CType::ToString, 0, CTYPESFN_FLAGS),
     326                 :   JS_FN("toSource", CType::ToSource, 0, CTYPESFN_FLAGS),
     327                 :   JS_FS_END
     328                 : };
     329                 : 
     330                 : static JSPropertySpec sCDataProps[] = {
     331                 :   { "value", 0, JSPROP_SHARED | JSPROP_PERMANENT,
     332                 :     CData::ValueGetter, CData::ValueSetter },
     333                 :   { 0, 0, 0, NULL, NULL }
     334                 : };
     335                 : 
     336                 : static JSFunctionSpec sCDataFunctions[] = {
     337                 :   JS_FN("address", CData::Address, 0, CDATAFN_FLAGS),
     338                 :   JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS),
     339                 :   JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS),
     340                 :   JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS),
     341                 :   JS_FS_END
     342                 : };
     343                 : 
     344                 : static JSFunctionSpec sPointerFunction =
     345                 :   JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS);
     346                 : 
     347                 : static JSPropertySpec sPointerProps[] = {
     348                 :   { "targetType", 0, CTYPESPROP_FLAGS, PointerType::TargetTypeGetter, NULL },
     349                 :   { 0, 0, 0, NULL, NULL }
     350                 : };
     351                 : 
     352                 : static JSFunctionSpec sPointerInstanceFunctions[] = {
     353                 :   JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS),
     354                 :   JS_FN("increment", PointerType::Increment, 0, CTYPESFN_FLAGS),
     355                 :   JS_FN("decrement", PointerType::Decrement, 0, CTYPESFN_FLAGS),
     356                 :   JS_FS_END
     357                 : };
     358                 :   
     359                 : static JSPropertySpec sPointerInstanceProps[] = {
     360                 :   { "contents", 0, JSPROP_SHARED | JSPROP_PERMANENT,
     361                 :     PointerType::ContentsGetter, PointerType::ContentsSetter },
     362                 :   { 0, 0, 0, NULL, NULL }
     363                 : };
     364                 : 
     365                 : static JSFunctionSpec sArrayFunction =
     366                 :   JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS);
     367                 : 
     368                 : static JSPropertySpec sArrayProps[] = {
     369                 :   { "elementType", 0, CTYPESPROP_FLAGS, ArrayType::ElementTypeGetter, NULL },
     370                 :   { "length", 0, CTYPESPROP_FLAGS, ArrayType::LengthGetter, NULL },
     371                 :   { 0, 0, 0, NULL, NULL }
     372                 : };
     373                 : 
     374                 : static JSFunctionSpec sArrayInstanceFunctions[] = {
     375                 :   JS_FN("addressOfElement", ArrayType::AddressOfElement, 1, CDATAFN_FLAGS),
     376                 :   JS_FS_END
     377                 : };
     378                 : 
     379                 : static JSPropertySpec sArrayInstanceProps[] = {
     380                 :   { "length", 0, JSPROP_SHARED | JSPROP_READONLY | JSPROP_PERMANENT,
     381                 :     ArrayType::LengthGetter, NULL },
     382                 :   { 0, 0, 0, NULL, NULL }
     383                 : };
     384                 : 
     385                 : static JSFunctionSpec sStructFunction =
     386                 :   JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS);
     387                 : 
     388                 : static JSPropertySpec sStructProps[] = {
     389                 :   { "fields", 0, CTYPESPROP_FLAGS, StructType::FieldsArrayGetter, NULL },
     390                 :   { 0, 0, 0, NULL, NULL }
     391                 : };
     392                 : 
     393                 : static JSFunctionSpec sStructFunctions[] = {
     394                 :   JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS),
     395                 :   JS_FS_END
     396                 : };
     397                 : 
     398                 : static JSFunctionSpec sStructInstanceFunctions[] = {
     399                 :   JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS),
     400                 :   JS_FS_END
     401                 : };
     402                 : 
     403                 : static JSFunctionSpec sFunctionFunction =
     404                 :   JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS);
     405                 : 
     406                 : static JSPropertySpec sFunctionProps[] = {
     407                 :   { "argTypes", 0, CTYPESPROP_FLAGS, FunctionType::ArgTypesGetter, NULL },
     408                 :   { "returnType", 0, CTYPESPROP_FLAGS, FunctionType::ReturnTypeGetter, NULL },
     409                 :   { "abi", 0, CTYPESPROP_FLAGS, FunctionType::ABIGetter, NULL },
     410                 :   { "isVariadic", 0, CTYPESPROP_FLAGS, FunctionType::IsVariadicGetter, NULL },
     411                 :   { 0, 0, 0, NULL, NULL }
     412                 : };
     413                 : 
     414                 : static JSFunctionSpec sFunctionInstanceFunctions[] = {
     415                 :   JS_FN("call", js_fun_call, 1, CDATAFN_FLAGS),
     416                 :   JS_FN("apply", js_fun_apply, 2, CDATAFN_FLAGS),
     417                 :   JS_FS_END
     418                 : };
     419                 : 
     420                 : static JSClass sInt64ProtoClass = {
     421                 :   "Int64",
     422                 :   0,
     423                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     424                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
     425                 : };
     426                 : 
     427                 : static JSClass sUInt64ProtoClass = {
     428                 :   "UInt64",
     429                 :   0,
     430                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     431                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
     432                 : };
     433                 : 
     434                 : static JSClass sInt64Class = {
     435                 :   "Int64",
     436                 :   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
     437                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     438                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
     439                 : };
     440                 : 
     441                 : static JSClass sUInt64Class = {
     442                 :   "UInt64",
     443                 :   JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS),
     444                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     445                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize
     446                 : };
     447                 : 
     448                 : static JSFunctionSpec sInt64StaticFunctions[] = {
     449                 :   JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS),
     450                 :   JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS),
     451                 :   JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS),
     452                 :   JS_FN("join", Int64::Join, 2, CTYPESFN_FLAGS),
     453                 :   JS_FS_END
     454                 : };
     455                 : 
     456                 : static JSFunctionSpec sUInt64StaticFunctions[] = {
     457                 :   JS_FN("compare", UInt64::Compare, 2, CTYPESFN_FLAGS),
     458                 :   JS_FN("lo", UInt64::Lo, 1, CTYPESFN_FLAGS),
     459                 :   JS_FN("hi", UInt64::Hi, 1, CTYPESFN_FLAGS),
     460                 :   JS_FN("join", UInt64::Join, 2, CTYPESFN_FLAGS),
     461                 :   JS_FS_END
     462                 : };
     463                 : 
     464                 : static JSFunctionSpec sInt64Functions[] = {
     465                 :   JS_FN("toString", Int64::ToString, 0, CTYPESFN_FLAGS),
     466                 :   JS_FN("toSource", Int64::ToSource, 0, CTYPESFN_FLAGS),
     467                 :   JS_FS_END
     468                 : };
     469                 : 
     470                 : static JSFunctionSpec sUInt64Functions[] = {
     471                 :   JS_FN("toString", UInt64::ToString, 0, CTYPESFN_FLAGS),
     472                 :   JS_FN("toSource", UInt64::ToSource, 0, CTYPESFN_FLAGS),
     473                 :   JS_FS_END
     474                 : };
     475                 : 
     476                 : static JSPropertySpec sModuleProps[] = {
     477                 :   { "errno", 0, JSPROP_SHARED | JSPROP_PERMANENT,
     478                 :     CData::ErrnoGetter, NULL },
     479                 : #if defined(XP_WIN)
     480                 :   { "winLastError", 0, JSPROP_SHARED | JSPROP_PERMANENT,
     481                 :     CData::LastErrorGetter, NULL },
     482                 : #endif // defined(XP_WIN)
     483                 :   { 0, 0, 0, NULL, NULL }
     484                 : };
     485                 : 
     486                 : static JSFunctionSpec sModuleFunctions[] = {
     487                 :   JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
     488                 :   JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
     489                 :   JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
     490                 :   JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
     491                 :   JS_FS_END
     492                 : };
     493                 : 
     494               0 : static inline bool FloatIsFinite(double f) {
     495                 : #ifdef WIN32
     496                 :   return _finite(f) != 0;
     497                 : #else
     498               0 :   return finite(f);
     499                 : #endif
     500                 : }
     501                 : 
     502                 : JS_ALWAYS_INLINE JSString*
     503               0 : NewUCString(JSContext* cx, const AutoString& from)
     504                 : {
     505               0 :   return JS_NewUCStringCopyN(cx, from.begin(), from.length());
     506                 : }
     507                 : 
     508                 : JS_ALWAYS_INLINE size_t
     509               0 : Align(size_t val, size_t align)
     510                 : {
     511               0 :   return ((val - 1) | (align - 1)) + 1;
     512                 : }
     513                 : 
     514                 : static ABICode
     515               0 : GetABICode(JSObject* obj)
     516                 : {
     517                 :   // make sure we have an object representing a CABI class,
     518                 :   // and extract the enumerated class type from the reserved slot.
     519               0 :   if (JS_GetClass(obj) != &sCABIClass)
     520               0 :     return INVALID_ABI;
     521                 : 
     522               0 :   jsval result = JS_GetReservedSlot(obj, SLOT_ABICODE);
     523               0 :   return ABICode(JSVAL_TO_INT(result));
     524                 : }
     525                 : 
     526                 : JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
     527                 : #define MSG_DEF(name, number, count, exception, format) \
     528                 :   { format, count, exception } ,
     529                 : #include "ctypes.msg"
     530                 : #undef MSG_DEF
     531                 : };
     532                 : 
     533                 : const JSErrorFormatString*
     534               0 : GetErrorMessage(void* userRef, const char* locale, const unsigned errorNumber)
     535                 : {
     536               0 :   if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
     537               0 :     return &ErrorFormatString[errorNumber];
     538               0 :   return NULL;
     539                 : }
     540                 : 
     541                 : JSBool
     542               0 : TypeError(JSContext* cx, const char* expected, jsval actual)
     543                 : {
     544               0 :   JSString* str = JS_ValueToSource(cx, actual);
     545               0 :   JSAutoByteString bytes;
     546                 :   
     547                 :   const char* src;
     548               0 :   if (str) {
     549               0 :     src = bytes.encode(cx, str);
     550               0 :     if (!src)
     551               0 :       return false;
     552                 :   } else {
     553               0 :     JS_ClearPendingException(cx);
     554               0 :     src = "<<error converting value to string>>";
     555                 :   }
     556                 :   JS_ReportErrorNumber(cx, GetErrorMessage, NULL,
     557               0 :                        CTYPESMSG_TYPE_ERROR, expected, src);
     558               0 :   return false;
     559                 : }
     560                 : 
     561                 : static JSObject*
     562           23328 : InitCTypeClass(JSContext* cx, JSObject* parent)
     563                 : {
     564                 :   JSFunction* fun = JS_DefineFunction(cx, parent, "CType", ConstructAbstract, 0,
     565           23328 :                       CTYPESCTOR_FLAGS);
     566           23328 :   if (!fun)
     567               0 :     return NULL;
     568                 : 
     569           23328 :   JSObject* ctor = JS_GetFunctionObject(fun);
     570           23328 :   JSObject* fnproto = JS_GetPrototype(ctor);
     571           23328 :   JS_ASSERT(ctor);
     572           23328 :   JS_ASSERT(fnproto);
     573                 : 
     574                 :   // Set up ctypes.CType.prototype.
     575           23328 :   JSObject* prototype = JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent);
     576           23328 :   if (!prototype)
     577               0 :     return NULL;
     578                 : 
     579           23328 :   if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype),
     580           23328 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     581               0 :     return NULL;
     582                 : 
     583           23328 :   if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor),
     584           23328 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     585               0 :     return NULL;
     586                 : 
     587                 :   // Define properties and functions common to all CTypes.
     588           46656 :   if (!JS_DefineProperties(cx, prototype, sCTypeProps) ||
     589           23328 :       !JS_DefineFunctions(cx, prototype, sCTypeFunctions))
     590               0 :     return NULL;
     591                 : 
     592           23328 :   if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
     593               0 :     return NULL;
     594                 : 
     595           23328 :   return prototype;
     596                 : }
     597                 : 
     598                 : static JSObject*
     599           23328 : InitCDataClass(JSContext* cx, JSObject* parent, JSObject* CTypeProto)
     600                 : {
     601                 :   JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0,
     602           23328 :                       CTYPESCTOR_FLAGS);
     603           23328 :   if (!fun)
     604               0 :     return NULL;
     605                 : 
     606           23328 :   JSObject* ctor = JS_GetFunctionObject(fun);
     607           23328 :   JS_ASSERT(ctor);
     608                 : 
     609                 :   // Set up ctypes.CData.__proto__ === ctypes.CType.prototype.
     610                 :   // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the
     611                 :   // prototype chain.)
     612           23328 :   if (!JS_SetPrototype(cx, ctor, CTypeProto))
     613               0 :     return NULL;
     614                 : 
     615                 :   // Set up ctypes.CData.prototype.
     616           23328 :   JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, NULL, parent);
     617           23328 :   if (!prototype)
     618               0 :     return NULL;
     619                 : 
     620           23328 :   if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype),
     621           23328 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     622               0 :     return NULL;
     623                 : 
     624           23328 :   if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor),
     625           23328 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     626               0 :     return NULL;
     627                 : 
     628                 :   // Define properties and functions common to all CDatas.
     629           46656 :   if (!JS_DefineProperties(cx, prototype, sCDataProps) ||
     630           23328 :       !JS_DefineFunctions(cx, prototype, sCDataFunctions))
     631               0 :     return NULL;
     632                 : 
     633           23328 :   if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
     634           23328 :       !JS_FreezeObject(cx, ctor))
     635               0 :     return NULL;
     636                 : 
     637           23328 :   return prototype;
     638                 : }
     639                 : 
     640                 : static JSBool
     641           69984 : DefineABIConstant(JSContext* cx,
     642                 :                   JSObject* parent,
     643                 :                   const char* name,
     644                 :                   ABICode code)
     645                 : {
     646                 :   JSObject* obj = JS_DefineObject(cx, parent, name, &sCABIClass, NULL,
     647           69984 :                     JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     648           69984 :   if (!obj)
     649               0 :     return false;
     650           69984 :   JS_SetReservedSlot(obj, SLOT_ABICODE, INT_TO_JSVAL(code));
     651           69984 :   return JS_FreezeObject(cx, obj);
     652                 : }
     653                 : 
     654                 : // Set up a single type constructor for
     655                 : // ctypes.{Pointer,Array,Struct,Function}Type.
     656                 : static JSBool
     657           93312 : InitTypeConstructor(JSContext* cx,
     658                 :                     JSObject* parent,
     659                 :                     JSObject* CTypeProto,
     660                 :                     JSObject* CDataProto,
     661                 :                     JSFunctionSpec spec,
     662                 :                     JSFunctionSpec* fns,
     663                 :                     JSPropertySpec* props,
     664                 :                     JSFunctionSpec* instanceFns,
     665                 :                     JSPropertySpec* instanceProps,
     666                 :                     JSObject*& typeProto,
     667                 :                     JSObject*& dataProto)
     668                 : {
     669                 :   JSFunction* fun = js::DefineFunctionWithReserved(cx, parent, spec.name, spec.call, 
     670           93312 :                       spec.nargs, spec.flags);
     671           93312 :   if (!fun)
     672               0 :     return false;
     673                 : 
     674           93312 :   JSObject* obj = JS_GetFunctionObject(fun);
     675           93312 :   if (!obj)
     676               0 :     return false;
     677                 : 
     678                 :   // Set up the .prototype and .prototype.constructor properties.
     679           93312 :   typeProto = JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent);
     680           93312 :   if (!typeProto)
     681               0 :     return false;
     682                 : 
     683                 :   // Define property before proceeding, for GC safety.
     684          186624 :   if (!JS_DefineProperty(cx, obj, "prototype", OBJECT_TO_JSVAL(typeProto),
     685           93312 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     686               0 :     return false;
     687                 : 
     688           93312 :   if (fns && !JS_DefineFunctions(cx, typeProto, fns))
     689               0 :     return false;
     690                 : 
     691           93312 :   if (!JS_DefineProperties(cx, typeProto, props))
     692               0 :     return false;
     693                 : 
     694           93312 :   if (!JS_DefineProperty(cx, typeProto, "constructor", OBJECT_TO_JSVAL(obj),
     695           93312 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     696               0 :     return false;
     697                 : 
     698                 :   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
     699                 :   // the type constructor, for faster lookup.
     700           93312 :   js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
     701                 : 
     702                 :   // Create an object to serve as the common ancestor for all CData objects
     703                 :   // created from the given type constructor. This has ctypes.CData.prototype
     704                 :   // as its prototype, such that it inherits the properties and functions
     705                 :   // common to all CDatas.
     706           93312 :   dataProto = JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent);
     707           93312 :   if (!dataProto)
     708               0 :     return false;
     709          186624 :   js::AutoObjectRooter protoroot(cx, dataProto);
     710                 : 
     711                 :   // Define functions and properties on the 'dataProto' object that are common
     712                 :   // to all CData objects created from this type constructor. (These will
     713                 :   // become functions and properties on CData objects created from this type.)
     714           93312 :   if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns))
     715               0 :     return false;
     716                 : 
     717           93312 :   if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps))
     718               0 :     return false;
     719                 : 
     720                 :   // Link the type prototype to the data prototype.
     721           93312 :   JS_SetReservedSlot(typeProto, SLOT_OURDATAPROTO, OBJECT_TO_JSVAL(dataProto));
     722                 : 
     723          186624 :   if (!JS_FreezeObject(cx, obj) ||
     724                 :       //!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
     725           93312 :       !JS_FreezeObject(cx, typeProto))
     726               0 :     return false;
     727                 : 
     728           93312 :   return true;
     729                 : }
     730                 : 
     731                 : JSObject*
     732           46656 : InitInt64Class(JSContext* cx,
     733                 :                JSObject* parent,
     734                 :                JSClass* clasp,
     735                 :                JSNative construct,
     736                 :                JSFunctionSpec* fs,
     737                 :                JSFunctionSpec* static_fs)
     738                 : {
     739                 :   // Init type class and constructor
     740                 :   JSObject* prototype = JS_InitClass(cx, parent, NULL, clasp, construct,
     741           46656 :     0, NULL, fs, NULL, static_fs);
     742           46656 :   if (!prototype)
     743               0 :     return NULL;
     744                 : 
     745           46656 :   JSObject* ctor = JS_GetConstructor(cx, prototype);
     746           46656 :   if (!ctor)
     747               0 :     return NULL;
     748           46656 :   if (!JS_FreezeObject(cx, ctor))
     749               0 :     return NULL;
     750                 : 
     751                 :   // Redefine the 'join' function as an extended native and stash
     752                 :   // ctypes.{Int64,UInt64}.prototype in a reserved slot of the new function.
     753           46656 :   JS_ASSERT(clasp == &sInt64ProtoClass || clasp == &sUInt64ProtoClass);
     754           46656 :   JSNative native = (clasp == &sInt64ProtoClass) ? Int64::Join : UInt64::Join;
     755                 :   JSFunction* fun = js::DefineFunctionWithReserved(cx, ctor, "join", native,
     756           46656 :                       2, CTYPESFN_FLAGS);
     757           46656 :   if (!fun)
     758               0 :     return NULL;
     759                 : 
     760                 :   js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO,
     761           46656 :     OBJECT_TO_JSVAL(prototype));
     762                 : 
     763           46656 :   if (!JS_FreezeObject(cx, prototype))
     764               0 :     return NULL;
     765                 : 
     766           46656 :   return prototype;
     767                 : }
     768                 : 
     769                 : static void
     770          116640 : AttachProtos(JSObject* proto, JSObject** protos)
     771                 : {
     772                 :   // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos'
     773                 :   // to the appropriate CTypeProtoSlot. (SLOT_CTYPES is the last slot
     774                 :   // of [[Class]] "CTypeProto" that we fill in this automated manner.)
     775         1516320 :   for (uint32_t i = 0; i <= SLOT_CTYPES; ++i)
     776         1399680 :     JS_SetReservedSlot(proto, i, OBJECT_TO_JSVAL(protos[i]));
     777          116640 : }
     778                 : 
     779                 : JSBool
     780           23328 : InitTypeClasses(JSContext* cx, JSObject* parent)
     781                 : {
     782                 :   // Initialize the ctypes.CType class. This acts as an abstract base class for
     783                 :   // the various types, and provides the common API functions. It has:
     784                 :   //   * [[Class]] "Function"
     785                 :   //   * __proto__ === Function.prototype
     786                 :   //   * A constructor that throws a TypeError. (You can't construct an
     787                 :   //     abstract type!)
     788                 :   //   * 'prototype' property:
     789                 :   //     * [[Class]] "CTypeProto"
     790                 :   //     * __proto__ === Function.prototype
     791                 :   //     * A constructor that throws a TypeError. (You can't construct an
     792                 :   //       abstract type instance!)
     793                 :   //     * 'constructor' property === ctypes.CType
     794                 :   //     * Provides properties and functions common to all CTypes.
     795           23328 :   JSObject* CTypeProto = InitCTypeClass(cx, parent);
     796           23328 :   if (!CTypeProto)
     797               0 :     return false;
     798                 : 
     799                 :   // Initialize the ctypes.CData class. This acts as an abstract base class for
     800                 :   // instances of the various types, and provides the common API functions.
     801                 :   // It has:
     802                 :   //   * [[Class]] "Function"
     803                 :   //   * __proto__ === Function.prototype
     804                 :   //   * A constructor that throws a TypeError. (You can't construct an
     805                 :   //     abstract type instance!)
     806                 :   //   * 'prototype' property:
     807                 :   //     * [[Class]] "CDataProto"
     808                 :   //     * 'constructor' property === ctypes.CData
     809                 :   //     * Provides properties and functions common to all CDatas.
     810           23328 :   JSObject* CDataProto = InitCDataClass(cx, parent, CTypeProto);
     811           23328 :   if (!CDataProto)
     812               0 :     return false;
     813                 : 
     814                 :   // Link CTypeProto to CDataProto.
     815                 :   JS_SetReservedSlot(CTypeProto, SLOT_OURDATAPROTO,
     816           23328 :                      OBJECT_TO_JSVAL(CDataProto));
     817                 : 
     818                 :   // Create and attach the special class constructors: ctypes.PointerType,
     819                 :   // ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType.
     820                 :   // Each of these constructors 'c' has, respectively:
     821                 :   //   * [[Class]] "Function"
     822                 :   //   * __proto__ === Function.prototype
     823                 :   //   * A constructor that creates a user-defined type.
     824                 :   //   * 'prototype' property:
     825                 :   //     * [[Class]] "CTypeProto"
     826                 :   //     * __proto__ === ctypes.CType.prototype
     827                 :   //     * 'constructor' property === 'c'
     828                 :   // We also construct an object 'p' to serve, given a type object 't'
     829                 :   // constructed from one of these type constructors, as
     830                 :   // 't.prototype.__proto__'. This object has:
     831                 :   //   * [[Class]] "CDataProto"
     832                 :   //   * __proto__ === ctypes.CData.prototype
     833                 :   //   * Properties and functions common to all CDatas.
     834                 :   // Therefore an instance 't' of ctypes.{Pointer,Array,Struct,Function}Type
     835                 :   // will have, resp.:
     836                 :   //   * [[Class]] "CType"
     837                 :   //   * __proto__ === ctypes.{Pointer,Array,Struct,Function}Type.prototype
     838                 :   //   * A constructor which creates and returns a CData object, containing
     839                 :   //     binary data of the given type.
     840                 :   //   * 'prototype' property:
     841                 :   //     * [[Class]] "CDataProto"
     842                 :   //     * __proto__ === 'p', the prototype object from above
     843                 :   //     * 'constructor' property === 't'
     844                 :   JSObject* protos[CTYPEPROTO_SLOTS];
     845           23328 :   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
     846                 :          sPointerFunction, NULL, sPointerProps,
     847                 :          sPointerInstanceFunctions, sPointerInstanceProps,
     848           23328 :          protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO]))
     849               0 :     return false;
     850           46656 :   js::AutoObjectRooter proot(cx, protos[SLOT_POINTERDATAPROTO]);
     851                 : 
     852           23328 :   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
     853                 :          sArrayFunction, NULL, sArrayProps,
     854                 :          sArrayInstanceFunctions, sArrayInstanceProps,
     855           23328 :          protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO]))
     856               0 :     return false;
     857           46656 :   js::AutoObjectRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]);
     858                 : 
     859           23328 :   if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
     860                 :          sStructFunction, sStructFunctions, sStructProps,
     861                 :          sStructInstanceFunctions, NULL,
     862           23328 :          protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO]))
     863               0 :     return false;
     864           46656 :   js::AutoObjectRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]);
     865                 : 
     866           23328 :   if (!InitTypeConstructor(cx, parent, CTypeProto, protos[SLOT_POINTERDATAPROTO],
     867                 :          sFunctionFunction, NULL, sFunctionProps, sFunctionInstanceFunctions, NULL,
     868           23328 :          protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO]))
     869               0 :     return false;
     870           46656 :   js::AutoObjectRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]);
     871                 : 
     872           23328 :   protos[SLOT_CDATAPROTO] = CDataProto;
     873                 : 
     874                 :   // Create and attach the ctypes.{Int64,UInt64} constructors.
     875                 :   // Each of these has, respectively:
     876                 :   //   * [[Class]] "Function"
     877                 :   //   * __proto__ === Function.prototype
     878                 :   //   * A constructor that creates a ctypes.{Int64,UInt64} object, respectively.
     879                 :   //   * 'prototype' property:
     880                 :   //     * [[Class]] {"Int64Proto","UInt64Proto"}
     881                 :   //     * 'constructor' property === ctypes.{Int64,UInt64}
     882                 :   protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass,
     883           23328 :     Int64::Construct, sInt64Functions, sInt64StaticFunctions);
     884           23328 :   if (!protos[SLOT_INT64PROTO])
     885               0 :     return false;
     886                 :   protos[SLOT_UINT64PROTO] = InitInt64Class(cx, parent, &sUInt64ProtoClass,
     887           23328 :     UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions);
     888           23328 :   if (!protos[SLOT_UINT64PROTO])
     889               0 :     return false;
     890                 : 
     891                 :   // Finally, store a pointer to the global ctypes object.
     892                 :   // Note that there is no other reliable manner of locating this object.
     893           23328 :   protos[SLOT_CTYPES] = parent;
     894                 : 
     895                 :   // Attach the prototypes just created to each of ctypes.CType.prototype,
     896                 :   // and the special type constructors, so we can access them when constructing
     897                 :   // instances of those types. 
     898           23328 :   AttachProtos(CTypeProto, protos);
     899           23328 :   AttachProtos(protos[SLOT_POINTERPROTO], protos);
     900           23328 :   AttachProtos(protos[SLOT_ARRAYPROTO], protos);
     901           23328 :   AttachProtos(protos[SLOT_STRUCTPROTO], protos);
     902           23328 :   AttachProtos(protos[SLOT_FUNCTIONPROTO], protos);
     903                 : 
     904                 :   // Attach objects representing ABI constants.
     905           69984 :   if (!DefineABIConstant(cx, parent, "default_abi", ABI_DEFAULT) ||
     906           23328 :       !DefineABIConstant(cx, parent, "stdcall_abi", ABI_STDCALL) ||
     907           23328 :       !DefineABIConstant(cx, parent, "winapi_abi", ABI_WINAPI))
     908               0 :     return false;
     909                 : 
     910                 :   // Create objects representing the builtin types, and attach them to the
     911                 :   // ctypes object. Each type object 't' has:
     912                 :   //   * [[Class]] "CType"
     913                 :   //   * __proto__ === ctypes.CType.prototype
     914                 :   //   * A constructor which creates and returns a CData object, containing
     915                 :   //     binary data of the given type.
     916                 :   //   * 'prototype' property:
     917                 :   //     * [[Class]] "CDataProto"
     918                 :   //     * __proto__ === ctypes.CData.prototype
     919                 :   //     * 'constructor' property === 't'
     920                 : #define DEFINE_TYPE(name, type, ffiType)                                       \
     921                 :   JSObject* typeObj_##name =                                                   \
     922                 :     CType::DefineBuiltin(cx, parent, #name, CTypeProto, CDataProto, #name,     \
     923                 :       TYPE_##name, INT_TO_JSVAL(sizeof(type)),                                 \
     924                 :       INT_TO_JSVAL(ffiType.alignment), &ffiType);                              \
     925                 :   if (!typeObj_##name)                                                         \
     926                 :     return false;
     927                 : #include "typedefs.h"
     928                 : 
     929                 :   // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
     930                 :   // the same type in C.
     931           23328 :   if (!JS_DefineProperty(cx, parent, "unsigned",
     932                 :          OBJECT_TO_JSVAL(typeObj_unsigned_int), NULL, NULL,
     933           23328 :          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     934               0 :     return false;
     935                 : 
     936                 :   // Create objects representing the special types void_t and voidptr_t.
     937                 :   JSObject* typeObj =
     938                 :     CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void",
     939           23328 :       TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void);
     940           23328 :   if (!typeObj)
     941               0 :     return false;
     942                 : 
     943           23328 :   typeObj = PointerType::CreateInternal(cx, typeObj);
     944           23328 :   if (!typeObj)
     945               0 :     return false;
     946           23328 :   if (!JS_DefineProperty(cx, parent, "voidptr_t", OBJECT_TO_JSVAL(typeObj),
     947           23328 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     948               0 :     return false;
     949                 : 
     950           23328 :   return true;
     951                 : }
     952                 : 
     953                 : bool
     954               0 : IsCTypesGlobal(JSObject* obj)
     955                 : {
     956               0 :   return JS_GetClass(obj) == &sCTypesGlobalClass;
     957                 : }
     958                 : 
     959                 : // Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'.
     960                 : JSCTypesCallbacks*
     961               0 : GetCallbacks(JSObject* obj)
     962                 : {
     963               0 :   JS_ASSERT(IsCTypesGlobal(obj));
     964                 : 
     965               0 :   jsval result = JS_GetReservedSlot(obj, SLOT_CALLBACKS);
     966               0 :   if (JSVAL_IS_VOID(result))
     967               0 :     return NULL;
     968                 : 
     969               0 :   return static_cast<JSCTypesCallbacks*>(JSVAL_TO_PRIVATE(result));
     970                 : }
     971                 : 
     972                 : JS_BEGIN_EXTERN_C
     973                 : 
     974                 : JS_PUBLIC_API(JSBool)
     975           23328 : JS_InitCTypesClass(JSContext* cx, JSObject* global)
     976                 : {
     977                 :   // attach ctypes property to global object
     978           23328 :   JSObject* ctypes = JS_NewObject(cx, &sCTypesGlobalClass, NULL, NULL);
     979           23328 :   if (!ctypes)
     980               0 :     return false;
     981                 : 
     982           23328 :   if (!JS_DefineProperty(cx, global, "ctypes", OBJECT_TO_JSVAL(ctypes),
     983           23328 :          JS_PropertyStub, JS_StrictPropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) {
     984               0 :     return false;
     985                 :   }
     986                 : 
     987           23328 :   if (!InitTypeClasses(cx, ctypes))
     988               0 :     return false;
     989                 : 
     990                 :   // attach API functions and properties
     991           46656 :   if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions) ||
     992           23328 :       !JS_DefineProperties(cx, ctypes, sModuleProps))
     993               0 :     return false;
     994                 : 
     995                 :   // Seal the ctypes object, to prevent modification.
     996           23328 :   return JS_FreezeObject(cx, ctypes);
     997                 : }
     998                 : 
     999                 : JS_PUBLIC_API(void)
    1000               0 : JS_SetCTypesCallbacks(JSObject* ctypesObj,
    1001                 :                       JSCTypesCallbacks* callbacks)
    1002                 : {
    1003               0 :   JS_ASSERT(callbacks);
    1004               0 :   JS_ASSERT(IsCTypesGlobal(ctypesObj));
    1005                 : 
    1006                 :   // Set the callbacks on a reserved slot.
    1007               0 :   JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS, PRIVATE_TO_JSVAL(callbacks));
    1008               0 : }
    1009                 : 
    1010                 : JS_END_EXTERN_C
    1011                 : 
    1012                 : /*******************************************************************************
    1013                 : ** Type conversion functions
    1014                 : *******************************************************************************/
    1015                 : 
    1016                 : // Enforce some sanity checks on type widths and properties.
    1017                 : // Where the architecture is 64-bit, make sure it's LP64 or LLP64. (ctypes.int
    1018                 : // autoconverts to a primitive JS number; to support ILP64 architectures, it
    1019                 : // would need to autoconvert to an Int64 object instead. Therefore we enforce
    1020                 : // this invariant here.)
    1021                 : JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4);
    1022                 : JS_STATIC_ASSERT(sizeof(char) == 1);
    1023                 : JS_STATIC_ASSERT(sizeof(short) == 2);
    1024                 : JS_STATIC_ASSERT(sizeof(int) == 4);
    1025                 : JS_STATIC_ASSERT(sizeof(unsigned) == 4);
    1026                 : JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
    1027                 : JS_STATIC_ASSERT(sizeof(long long) == 8);
    1028                 : JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
    1029                 : JS_STATIC_ASSERT(sizeof(float) == 4);
    1030                 : JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
    1031                 : JS_STATIC_ASSERT(numeric_limits<double>::is_signed);
    1032                 : 
    1033                 : // Templated helper to convert FromType to TargetType, for the default case
    1034                 : // where the trivial POD constructor will do.
    1035                 : template<class TargetType, class FromType>
    1036                 : struct ConvertImpl {
    1037               0 :   static JS_ALWAYS_INLINE TargetType Convert(FromType d) {
    1038               0 :     return TargetType(d);
    1039                 :   }
    1040                 : };
    1041                 : 
    1042                 : #ifdef _MSC_VER
    1043                 : // MSVC can't perform double to unsigned __int64 conversion when the
    1044                 : // double is greater than 2^63 - 1. Help it along a little.
    1045                 : template<>
    1046                 : struct ConvertImpl<uint64_t, double> {
    1047                 :   static JS_ALWAYS_INLINE uint64_t Convert(double d) {
    1048                 :     return d > 0x7fffffffffffffffui64 ?
    1049                 :            uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
    1050                 :            uint64_t(d);
    1051                 :   }
    1052                 : };
    1053                 : #endif
    1054                 : 
    1055                 : // C++ doesn't guarantee that exact values are the only ones that will
    1056                 : // round-trip. In fact, on some platforms, including SPARC, there are pairs of
    1057                 : // values, a uint64_t and a double, such that neither value is exactly
    1058                 : // representable in the other type, but they cast to each other.
    1059                 : #ifdef SPARC
    1060                 : // Simulate x86 overflow behavior
    1061                 : template<>
    1062                 : struct ConvertImpl<uint64_t, double> {
    1063                 :   static JS_ALWAYS_INLINE uint64_t Convert(double d) {
    1064                 :     return d >= 0xffffffffffffffff ?
    1065                 :            0x8000000000000000 : uint64_t(d);
    1066                 :   }
    1067                 : };
    1068                 : 
    1069                 : template<>
    1070                 : struct ConvertImpl<int64_t, double> {
    1071                 :   static JS_ALWAYS_INLINE int64_t Convert(double d) {
    1072                 :     return d >= 0x7fffffffffffffff ?
    1073                 :            0x8000000000000000 : int64_t(d);
    1074                 :   }
    1075                 : };
    1076                 : #endif
    1077                 : 
    1078                 : template<class TargetType, class FromType>
    1079               0 : static JS_ALWAYS_INLINE TargetType Convert(FromType d)
    1080                 : {
    1081               0 :   return ConvertImpl<TargetType, FromType>::Convert(d);
    1082                 : }
    1083                 : 
    1084                 : template<class TargetType, class FromType>
    1085               0 : static JS_ALWAYS_INLINE bool IsAlwaysExact()
    1086                 : {
    1087                 :   // Return 'true' if TargetType can always exactly represent FromType.
    1088                 :   // This means that:
    1089                 :   // 1) TargetType must be the same or more bits wide as FromType. For integers
    1090                 :   //    represented in 'n' bits, unsigned variants will have 'n' digits while
    1091                 :   //    signed will have 'n - 1'. For floating point types, 'digits' is the
    1092                 :   //    mantissa width.
    1093                 :   // 2) If FromType is signed, TargetType must also be signed. (Floating point
    1094                 :   //    types are always signed.)
    1095                 :   // 3) If TargetType is an exact integral type, FromType must be also.
    1096                 :   if (numeric_limits<TargetType>::digits < numeric_limits<FromType>::digits)
    1097               0 :     return false;
    1098                 : 
    1099                 :   if (numeric_limits<FromType>::is_signed &&
    1100                 :       !numeric_limits<TargetType>::is_signed)
    1101               0 :     return false;
    1102                 : 
    1103                 :   if (!numeric_limits<FromType>::is_exact &&
    1104                 :       numeric_limits<TargetType>::is_exact)
    1105               0 :     return false;
    1106                 : 
    1107               0 :   return true;
    1108                 : }
    1109                 : 
    1110                 : // Templated helper to determine if FromType 'i' converts losslessly to
    1111                 : // TargetType 'j'. Default case where both types are the same signedness.
    1112                 : template<class TargetType, class FromType, bool TargetSigned, bool FromSigned>
    1113                 : struct IsExactImpl {
    1114               0 :   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    1115                 :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    1116               0 :     return FromType(j) == i;
    1117                 :   }
    1118                 : };
    1119                 : 
    1120                 : // Specialization where TargetType is unsigned, FromType is signed.
    1121                 : template<class TargetType, class FromType>
    1122                 : struct IsExactImpl<TargetType, FromType, false, true> {
    1123               0 :   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    1124                 :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    1125               0 :     return i >= 0 && FromType(j) == i;
    1126                 :   }
    1127                 : };
    1128                 : 
    1129                 : // Specialization where TargetType is signed, FromType is unsigned.
    1130                 : template<class TargetType, class FromType>
    1131                 : struct IsExactImpl<TargetType, FromType, true, false> {
    1132               0 :   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
    1133                 :     JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    1134               0 :     return TargetType(i) >= 0 && FromType(j) == i;
    1135                 :   }
    1136                 : };
    1137                 : 
    1138                 : // Convert FromType 'i' to TargetType 'result', returning true iff 'result'
    1139                 : // is an exact representation of 'i'.
    1140                 : template<class TargetType, class FromType>
    1141               0 : static JS_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
    1142                 : {
    1143                 :   // Require that TargetType is integral, to simplify conversion.
    1144                 :   JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
    1145                 : 
    1146               0 :   *result = Convert<TargetType>(i);
    1147                 : 
    1148                 :   // See if we can avoid a dynamic check.
    1149               0 :   if (IsAlwaysExact<TargetType, FromType>())
    1150               0 :     return true;
    1151                 : 
    1152                 :   // Return 'true' if 'i' is exactly representable in 'TargetType'.
    1153                 :   return IsExactImpl<TargetType,
    1154                 :                      FromType,
    1155                 :                      numeric_limits<TargetType>::is_signed,
    1156               0 :                      numeric_limits<FromType>::is_signed>::Test(i, *result);
    1157                 : }
    1158                 : 
    1159                 : // Templated helper to determine if Type 'i' is negative. Default case
    1160                 : // where IntegerType is unsigned.
    1161                 : template<class Type, bool IsSigned>
    1162                 : struct IsNegativeImpl {
    1163               0 :   static JS_ALWAYS_INLINE bool Test(Type i) {
    1164               0 :     return false;
    1165                 :   }
    1166                 : };
    1167                 : 
    1168                 : // Specialization where Type is signed.
    1169                 : template<class Type>
    1170                 : struct IsNegativeImpl<Type, true> {
    1171               0 :   static JS_ALWAYS_INLINE bool Test(Type i) {
    1172               0 :     return i < 0;
    1173                 :   }
    1174                 : };
    1175                 : 
    1176                 : // Determine whether Type 'i' is negative.
    1177                 : template<class Type>
    1178               0 : static JS_ALWAYS_INLINE bool IsNegative(Type i)
    1179                 : {
    1180               0 :   return IsNegativeImpl<Type, numeric_limits<Type>::is_signed>::Test(i);
    1181                 : }
    1182                 : 
    1183                 : // Implicitly convert val to bool, allowing JSBool, int, and double
    1184                 : // arguments numerically equal to 0 or 1.
    1185                 : static bool
    1186               0 : jsvalToBool(JSContext* cx, jsval val, bool* result)
    1187                 : {
    1188               0 :   if (JSVAL_IS_BOOLEAN(val)) {
    1189               0 :     *result = JSVAL_TO_BOOLEAN(val) != JS_FALSE;
    1190               0 :     return true;
    1191                 :   }
    1192               0 :   if (JSVAL_IS_INT(val)) {
    1193               0 :     int32_t i = JSVAL_TO_INT(val);
    1194               0 :     *result = i != 0;
    1195               0 :     return i == 0 || i == 1;
    1196                 :   }
    1197               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1198               0 :     double d = JSVAL_TO_DOUBLE(val);
    1199               0 :     *result = d != 0;
    1200                 :     // Allow -0.
    1201               0 :     return d == 1 || d == 0;
    1202                 :   }
    1203                 :   // Don't silently convert null to bool. It's probably a mistake.
    1204               0 :   return false;
    1205                 : }
    1206                 : 
    1207                 : // Implicitly convert val to IntegerType, allowing JSBool, int, double,
    1208                 : // Int64, UInt64, and CData integer types 't' where all values of 't' are
    1209                 : // representable by IntegerType.
    1210                 : template<class IntegerType>
    1211                 : static bool
    1212               0 : jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
    1213                 : {
    1214                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1215                 : 
    1216               0 :   if (JSVAL_IS_INT(val)) {
    1217                 :     // Make sure the integer fits in the alotted precision, and has the right
    1218                 :     // sign.
    1219               0 :     int32_t i = JSVAL_TO_INT(val);
    1220               0 :     return ConvertExact(i, result);
    1221                 :   }
    1222               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1223                 :     // Don't silently lose bits here -- check that val really is an
    1224                 :     // integer value, and has the right sign.
    1225               0 :     double d = JSVAL_TO_DOUBLE(val);
    1226               0 :     return ConvertExact(d, result);
    1227                 :   }
    1228               0 :   if (!JSVAL_IS_PRIMITIVE(val)) {
    1229               0 :     JSObject* obj = JSVAL_TO_OBJECT(val);
    1230               0 :     if (CData::IsCData(obj)) {
    1231               0 :       JSObject* typeObj = CData::GetCType(obj);
    1232               0 :       void* data = CData::GetData(obj);
    1233                 : 
    1234                 :       // Check whether the source type is always representable, with exact
    1235                 :       // precision, by the target type. If it is, convert the value.
    1236               0 :       switch (CType::GetTypeCode(typeObj)) {
    1237                 : #define DEFINE_INT_TYPE(name, fromType, ffiType)                               \
    1238                 :       case TYPE_##name:                                                        \
    1239                 :         if (!IsAlwaysExact<IntegerType, fromType>())                           \
    1240                 :           return false;                                                        \
    1241                 :         *result = IntegerType(*static_cast<fromType*>(data));                  \
    1242                 :         return true;
    1243                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    1244                 : #include "typedefs.h"
    1245                 :       case TYPE_void_t:
    1246                 :       case TYPE_bool:
    1247                 :       case TYPE_float:
    1248                 :       case TYPE_double:
    1249                 :       case TYPE_float32_t:
    1250                 :       case TYPE_float64_t:
    1251                 :       case TYPE_char:
    1252                 :       case TYPE_signed_char:
    1253                 :       case TYPE_unsigned_char:
    1254                 :       case TYPE_jschar:
    1255                 :       case TYPE_pointer:
    1256                 :       case TYPE_function:
    1257                 :       case TYPE_array:
    1258                 :       case TYPE_struct:
    1259                 :         // Not a compatible number type.
    1260               0 :         return false;
    1261                 :       }
    1262                 :     }
    1263                 : 
    1264               0 :     if (Int64::IsInt64(obj)) {
    1265                 :       // Make sure the integer fits in IntegerType.
    1266               0 :       int64_t i = Int64Base::GetInt(obj);
    1267               0 :       return ConvertExact(i, result);
    1268                 :     }
    1269                 : 
    1270               0 :     if (UInt64::IsUInt64(obj)) {
    1271                 :       // Make sure the integer fits in IntegerType.
    1272               0 :       uint64_t i = Int64Base::GetInt(obj);
    1273               0 :       return ConvertExact(i, result);
    1274                 :     }
    1275                 : 
    1276               0 :     return false; 
    1277                 :   }
    1278               0 :   if (JSVAL_IS_BOOLEAN(val)) {
    1279                 :     // Implicitly promote boolean values to 0 or 1, like C.
    1280               0 :     *result = JSVAL_TO_BOOLEAN(val);
    1281               0 :     JS_ASSERT(*result == 0 || *result == 1);
    1282               0 :     return true;
    1283                 :   }
    1284                 :   // Don't silently convert null to an integer. It's probably a mistake.
    1285               0 :   return false;
    1286                 : }
    1287                 : 
    1288                 : // Implicitly convert val to FloatType, allowing int, double,
    1289                 : // Int64, UInt64, and CData numeric types 't' where all values of 't' are
    1290                 : // representable by FloatType.
    1291                 : template<class FloatType>
    1292                 : static bool
    1293               0 : jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
    1294                 : {
    1295                 :   JS_STATIC_ASSERT(!numeric_limits<FloatType>::is_exact);
    1296                 : 
    1297                 :   // The following casts may silently throw away some bits, but there's
    1298                 :   // no good way around it. Sternly requiring that the 64-bit double
    1299                 :   // argument be exactly representable as a 32-bit float is
    1300                 :   // unrealistic: it would allow 1/2 to pass but not 1/3.
    1301               0 :   if (JSVAL_IS_INT(val)) {
    1302               0 :     *result = FloatType(JSVAL_TO_INT(val));
    1303               0 :     return true;
    1304                 :   }
    1305               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1306               0 :     *result = FloatType(JSVAL_TO_DOUBLE(val));
    1307               0 :     return true;
    1308                 :   }
    1309               0 :   if (!JSVAL_IS_PRIMITIVE(val)) {
    1310               0 :     JSObject* obj = JSVAL_TO_OBJECT(val);
    1311               0 :     if (CData::IsCData(obj)) {
    1312               0 :       JSObject* typeObj = CData::GetCType(obj);
    1313               0 :       void* data = CData::GetData(obj);
    1314                 : 
    1315                 :       // Check whether the source type is always representable, with exact
    1316                 :       // precision, by the target type. If it is, convert the value.
    1317               0 :       switch (CType::GetTypeCode(typeObj)) {
    1318                 : #define DEFINE_FLOAT_TYPE(name, fromType, ffiType)                             \
    1319                 :       case TYPE_##name:                                                        \
    1320                 :         if (!IsAlwaysExact<FloatType, fromType>())                             \
    1321                 :           return false;                                                        \
    1322                 :         *result = FloatType(*static_cast<fromType*>(data));                    \
    1323                 :         return true;
    1324                 : #define DEFINE_INT_TYPE(x, y, z) DEFINE_FLOAT_TYPE(x, y, z)
    1325                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    1326                 : #include "typedefs.h"
    1327                 :       case TYPE_void_t:
    1328                 :       case TYPE_bool:
    1329                 :       case TYPE_char:
    1330                 :       case TYPE_signed_char:
    1331                 :       case TYPE_unsigned_char:
    1332                 :       case TYPE_jschar:
    1333                 :       case TYPE_pointer:
    1334                 :       case TYPE_function:
    1335                 :       case TYPE_array:
    1336                 :       case TYPE_struct:
    1337                 :         // Not a compatible number type.
    1338               0 :         return false;
    1339                 :       }
    1340                 :     }
    1341                 :   }
    1342                 :   // Don't silently convert true to 1.0 or false to 0.0, even though C/C++
    1343                 :   // does it. It's likely to be a mistake.
    1344               0 :   return false;
    1345                 : }
    1346                 : 
    1347                 : template<class IntegerType>
    1348                 : static bool
    1349               0 : StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
    1350                 : {
    1351                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1352                 : 
    1353               0 :   const jschar* cp = string->getChars(NULL);
    1354               0 :   if (!cp)
    1355               0 :     return false;
    1356                 : 
    1357               0 :   const jschar* end = cp + string->length();
    1358               0 :   if (cp == end)
    1359               0 :     return false;
    1360                 : 
    1361               0 :   IntegerType sign = 1;
    1362               0 :   if (cp[0] == '-') {
    1363                 :     if (!numeric_limits<IntegerType>::is_signed)
    1364               0 :       return false;
    1365                 : 
    1366               0 :     sign = -1;
    1367               0 :     ++cp;
    1368                 :   }
    1369                 : 
    1370                 :   // Assume base-10, unless the string begins with '0x' or '0X'.
    1371               0 :   IntegerType base = 10;
    1372               0 :   if (end - cp > 2 && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) {
    1373               0 :     cp += 2;
    1374               0 :     base = 16;
    1375                 :   }
    1376                 : 
    1377                 :   // Scan the string left to right and build the number,
    1378                 :   // checking for valid characters 0 - 9, a - f, A - F and overflow.
    1379               0 :   IntegerType i = 0;
    1380               0 :   while (cp != end) {
    1381               0 :     jschar c = *cp++;
    1382               0 :     if (c >= '0' && c <= '9')
    1383               0 :       c -= '0';
    1384               0 :     else if (base == 16 && c >= 'a' && c <= 'f')
    1385               0 :       c = c - 'a' + 10;
    1386               0 :     else if (base == 16 && c >= 'A' && c <= 'F')
    1387               0 :       c = c - 'A' + 10;
    1388                 :     else
    1389               0 :       return false;
    1390                 : 
    1391               0 :     IntegerType ii = i;
    1392               0 :     i = ii * base + sign * c;
    1393               0 :     if (i / base != ii) // overflow
    1394               0 :       return false;
    1395                 :   }
    1396                 : 
    1397               0 :   *result = i;
    1398               0 :   return true;
    1399                 : }
    1400                 : 
    1401                 : // Implicitly convert val to IntegerType, allowing int, double,
    1402                 : // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
    1403                 : // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
    1404                 : template<class IntegerType>
    1405                 : static bool
    1406               0 : jsvalToBigInteger(JSContext* cx,
    1407                 :                   jsval val,
    1408                 :                   bool allowString,
    1409                 :                   IntegerType* result)
    1410                 : {
    1411                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1412                 : 
    1413               0 :   if (JSVAL_IS_INT(val)) {
    1414                 :     // Make sure the integer fits in the alotted precision, and has the right
    1415                 :     // sign.
    1416               0 :     int32_t i = JSVAL_TO_INT(val);
    1417               0 :     return ConvertExact(i, result);
    1418                 :   }
    1419               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1420                 :     // Don't silently lose bits here -- check that val really is an
    1421                 :     // integer value, and has the right sign.
    1422               0 :     double d = JSVAL_TO_DOUBLE(val);
    1423               0 :     return ConvertExact(d, result);
    1424                 :   }
    1425               0 :   if (allowString && JSVAL_IS_STRING(val)) {
    1426                 :     // Allow conversion from base-10 or base-16 strings, provided the result
    1427                 :     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
    1428                 :     // to the JS array element operator, which will automatically call
    1429                 :     // toString() on the object for us.)
    1430               0 :     return StringToInteger(cx, JSVAL_TO_STRING(val), result);
    1431                 :   }
    1432               0 :   if (!JSVAL_IS_PRIMITIVE(val)) {
    1433                 :     // Allow conversion from an Int64 or UInt64 object directly.
    1434               0 :     JSObject* obj = JSVAL_TO_OBJECT(val);
    1435                 : 
    1436               0 :     if (UInt64::IsUInt64(obj)) {
    1437                 :       // Make sure the integer fits in IntegerType.
    1438               0 :       uint64_t i = Int64Base::GetInt(obj);
    1439               0 :       return ConvertExact(i, result);
    1440                 :     }
    1441                 : 
    1442               0 :     if (Int64::IsInt64(obj)) {
    1443                 :       // Make sure the integer fits in IntegerType.
    1444               0 :       int64_t i = Int64Base::GetInt(obj);
    1445               0 :       return ConvertExact(i, result);
    1446                 :     }
    1447                 :   }
    1448               0 :   return false;
    1449                 : }
    1450                 : 
    1451                 : // Implicitly convert val to a size value, where the size value is represented
    1452                 : // by size_t but must also fit in a double.
    1453                 : static bool
    1454               0 : jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result)
    1455                 : {
    1456               0 :   if (!jsvalToBigInteger(cx, val, allowString, result))
    1457               0 :     return false;
    1458                 : 
    1459                 :   // Also check that the result fits in a double.
    1460               0 :   return Convert<size_t>(double(*result)) == *result;
    1461                 : }
    1462                 : 
    1463                 : // Implicitly convert val to IntegerType, allowing int, double,
    1464                 : // Int64, UInt64, and optionally a decimal or hexadecimal string argument.
    1465                 : // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
    1466                 : template<class IntegerType>
    1467                 : static bool
    1468               0 : jsidToBigInteger(JSContext* cx,
    1469                 :                   jsid val,
    1470                 :                   bool allowString,
    1471                 :                   IntegerType* result)
    1472                 : {
    1473                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1474                 : 
    1475               0 :   if (JSID_IS_INT(val)) {
    1476                 :     // Make sure the integer fits in the alotted precision, and has the right
    1477                 :     // sign.
    1478               0 :     int32_t i = JSID_TO_INT(val);
    1479               0 :     return ConvertExact(i, result);
    1480                 :   }
    1481               0 :   if (allowString && JSID_IS_STRING(val)) {
    1482                 :     // Allow conversion from base-10 or base-16 strings, provided the result
    1483                 :     // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed
    1484                 :     // to the JS array element operator, which will automatically call
    1485                 :     // toString() on the object for us.)
    1486               0 :     return StringToInteger(cx, JSID_TO_STRING(val), result);
    1487                 :   }
    1488               0 :   if (JSID_IS_OBJECT(val)) {
    1489                 :     // Allow conversion from an Int64 or UInt64 object directly.
    1490               0 :     JSObject* obj = JSID_TO_OBJECT(val);
    1491                 : 
    1492               0 :     if (UInt64::IsUInt64(obj)) {
    1493                 :       // Make sure the integer fits in IntegerType.
    1494               0 :       uint64_t i = Int64Base::GetInt(obj);
    1495               0 :       return ConvertExact(i, result);
    1496                 :     }
    1497                 : 
    1498               0 :     if (Int64::IsInt64(obj)) {
    1499                 :       // Make sure the integer fits in IntegerType.
    1500               0 :       int64_t i = Int64Base::GetInt(obj);
    1501               0 :       return ConvertExact(i, result);
    1502                 :     }
    1503                 :   }
    1504               0 :   return false;
    1505                 : }
    1506                 : 
    1507                 : // Implicitly convert val to a size value, where the size value is represented
    1508                 : // by size_t but must also fit in a double.
    1509                 : static bool
    1510               0 : jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result)
    1511                 : {
    1512               0 :   if (!jsidToBigInteger(cx, val, allowString, result))
    1513               0 :     return false;
    1514                 : 
    1515                 :   // Also check that the result fits in a double.
    1516               0 :   return Convert<size_t>(double(*result)) == *result;
    1517                 : }
    1518                 : 
    1519                 : // Implicitly convert a size value to a jsval, ensuring that the size_t value
    1520                 : // fits in a double.
    1521                 : static JSBool
    1522               0 : SizeTojsval(JSContext* cx, size_t size, jsval* result)
    1523                 : {
    1524               0 :   if (Convert<size_t>(double(size)) != size) {
    1525               0 :     JS_ReportError(cx, "size overflow");
    1526               0 :     return false;
    1527                 :   }
    1528                 : 
    1529               0 :   return JS_NewNumberValue(cx, double(size), result);
    1530                 : }
    1531                 : 
    1532                 : // Forcefully convert val to IntegerType when explicitly requested.
    1533                 : template<class IntegerType>
    1534                 : static bool
    1535               0 : jsvalToIntegerExplicit(jsval val, IntegerType* result)
    1536                 : {
    1537                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1538                 : 
    1539               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1540                 :     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
    1541               0 :     double d = JSVAL_TO_DOUBLE(val);
    1542               0 :     *result = FloatIsFinite(d) ? IntegerType(d) : 0;
    1543               0 :     return true;
    1544                 :   }
    1545               0 :   if (!JSVAL_IS_PRIMITIVE(val)) {
    1546                 :     // Convert Int64 and UInt64 values by C-style cast.
    1547               0 :     JSObject* obj = JSVAL_TO_OBJECT(val);
    1548               0 :     if (Int64::IsInt64(obj)) {
    1549               0 :       int64_t i = Int64Base::GetInt(obj);
    1550               0 :       *result = IntegerType(i);
    1551               0 :       return true;
    1552                 :     }
    1553               0 :     if (UInt64::IsUInt64(obj)) {
    1554               0 :       uint64_t i = Int64Base::GetInt(obj);
    1555               0 :       *result = IntegerType(i);
    1556               0 :       return true;
    1557                 :     }
    1558                 :   }
    1559               0 :   return false;
    1560                 : }
    1561                 : 
    1562                 : // Forcefully convert val to a pointer value when explicitly requested.
    1563                 : static bool
    1564               0 : jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
    1565                 : {
    1566               0 :   if (JSVAL_IS_INT(val)) {
    1567                 :     // int32_t always fits in intptr_t. If the integer is negative, cast through
    1568                 :     // an intptr_t intermediate to sign-extend.
    1569               0 :     int32_t i = JSVAL_TO_INT(val);
    1570               0 :     *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
    1571               0 :     return true;
    1572                 :   }
    1573               0 :   if (JSVAL_IS_DOUBLE(val)) {
    1574               0 :     double d = JSVAL_TO_DOUBLE(val);
    1575               0 :     if (d < 0) {
    1576                 :       // Cast through an intptr_t intermediate to sign-extend.
    1577               0 :       intptr_t i = Convert<intptr_t>(d);
    1578               0 :       if (double(i) != d)
    1579               0 :         return false;
    1580                 : 
    1581               0 :       *result = uintptr_t(i);
    1582               0 :       return true;
    1583                 :     }
    1584                 : 
    1585                 :     // Don't silently lose bits here -- check that val really is an
    1586                 :     // integer value, and has the right sign.
    1587               0 :     *result = Convert<uintptr_t>(d);
    1588               0 :     return double(*result) == d;
    1589                 :   }
    1590               0 :   if (!JSVAL_IS_PRIMITIVE(val)) {
    1591               0 :     JSObject* obj = JSVAL_TO_OBJECT(val);
    1592               0 :     if (Int64::IsInt64(obj)) {
    1593               0 :       int64_t i = Int64Base::GetInt(obj);
    1594               0 :       intptr_t p = intptr_t(i);
    1595                 : 
    1596                 :       // Make sure the integer fits in the alotted precision.
    1597               0 :       if (int64_t(p) != i)
    1598               0 :         return false;
    1599               0 :       *result = uintptr_t(p);
    1600               0 :       return true;
    1601                 :     }
    1602                 : 
    1603               0 :     if (UInt64::IsUInt64(obj)) {
    1604               0 :       uint64_t i = Int64Base::GetInt(obj);
    1605                 : 
    1606                 :       // Make sure the integer fits in the alotted precision.
    1607               0 :       *result = uintptr_t(i);
    1608               0 :       return uint64_t(*result) == i;
    1609                 :     }
    1610                 :   }
    1611               0 :   return false;
    1612                 : }
    1613                 : 
    1614                 : template<class IntegerType, class CharType, size_t N, class AP>
    1615                 : void
    1616               0 : IntegerToString(IntegerType i, int radix, Vector<CharType, N, AP>& result)
    1617                 : {
    1618                 :   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
    1619                 : 
    1620                 :   // The buffer must be big enough for all the bits of IntegerType to fit,
    1621                 :   // in base-2, including '-'.
    1622                 :   CharType buffer[sizeof(IntegerType) * 8 + 1];
    1623               0 :   CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
    1624               0 :   CharType* cp = end;
    1625                 : 
    1626                 :   // Build the string in reverse. We use multiplication and subtraction
    1627                 :   // instead of modulus because that's much faster.
    1628               0 :   const bool isNegative = IsNegative(i);
    1629               0 :   size_t sign = isNegative ? -1 : 1;
    1630               0 :   do {
    1631               0 :     IntegerType ii = i / IntegerType(radix);
    1632               0 :     size_t index = sign * size_t(i - ii * IntegerType(radix));
    1633               0 :     *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[index];
    1634               0 :     i = ii;
    1635                 :   } while (i != 0);
    1636                 : 
    1637               0 :   if (isNegative)
    1638               0 :     *--cp = '-';
    1639                 : 
    1640               0 :   JS_ASSERT(cp >= buffer);
    1641               0 :   result.append(cp, end);
    1642               0 : }
    1643                 : 
    1644                 : template<class CharType>
    1645                 : static size_t
    1646               0 : strnlen(const CharType* begin, size_t max)
    1647                 : {
    1648               0 :   for (const CharType* s = begin; s != begin + max; ++s)
    1649               0 :     if (*s == 0)
    1650               0 :       return s - begin;
    1651                 : 
    1652               0 :   return max;
    1653                 : }
    1654                 : 
    1655                 : // Convert C binary value 'data' of CType 'typeObj' to a JS primitive, where
    1656                 : // possible; otherwise, construct and return a CData object. The following
    1657                 : // semantics apply when constructing a CData object for return:
    1658                 : // * If 'wantPrimitive' is true, the caller indicates that 'result' must be
    1659                 : //   a JS primitive, and ConvertToJS will fail if 'result' would be a CData
    1660                 : //   object. Otherwise:
    1661                 : // * If a CData object 'parentObj' is supplied, the new CData object is
    1662                 : //   dependent on the given parent and its buffer refers to a slice of the
    1663                 : //   parent's buffer.
    1664                 : // * If 'parentObj' is null, the new CData object may or may not own its
    1665                 : //   resulting buffer depending on the 'ownResult' argument.
    1666                 : JSBool
    1667               0 : ConvertToJS(JSContext* cx,
    1668                 :             JSObject* typeObj,
    1669                 :             JSObject* parentObj,
    1670                 :             void* data,
    1671                 :             bool wantPrimitive,
    1672                 :             bool ownResult,
    1673                 :             jsval* result)
    1674                 : {
    1675               0 :   JS_ASSERT(!parentObj || CData::IsCData(parentObj));
    1676               0 :   JS_ASSERT(!parentObj || !ownResult);
    1677               0 :   JS_ASSERT(!wantPrimitive || !ownResult);
    1678                 : 
    1679               0 :   TypeCode typeCode = CType::GetTypeCode(typeObj);
    1680                 : 
    1681               0 :   switch (typeCode) {
    1682                 :   case TYPE_void_t:
    1683               0 :     *result = JSVAL_VOID;
    1684               0 :     break;
    1685                 :   case TYPE_bool:
    1686               0 :     *result = *static_cast<bool*>(data) ? JSVAL_TRUE : JSVAL_FALSE;
    1687               0 :     break;
    1688                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    1689                 :   case TYPE_##name: {                                                          \
    1690                 :     type value = *static_cast<type*>(data);                                    \
    1691                 :     if (sizeof(type) < 4)                                                      \
    1692                 :       *result = INT_TO_JSVAL(int32_t(value));                                    \
    1693                 :     else if (!JS_NewNumberValue(cx, double(value), result))                    \
    1694                 :       return false;                                                            \
    1695                 :     break;                                                                     \
    1696                 :   }
    1697                 : #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
    1698                 :   case TYPE_##name: {                                                          \
    1699                 :     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
    1700                 :     uint64_t value;                                                            \
    1701                 :     JSObject* proto;                                                           \
    1702                 :     if (!numeric_limits<type>::is_signed) {                                    \
    1703                 :       value = *static_cast<type*>(data);                                       \
    1704                 :       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
    1705                 :       proto = CType::GetProtoFromType(typeObj, SLOT_UINT64PROTO);              \
    1706                 :     } else {                                                                   \
    1707                 :       value = int64_t(*static_cast<type*>(data));                              \
    1708                 :       /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */            \
    1709                 :       proto = CType::GetProtoFromType(typeObj, SLOT_INT64PROTO);               \
    1710                 :     }                                                                          \
    1711                 :                                                                                \
    1712                 :     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
    1713                 :       !numeric_limits<type>::is_signed);                                       \
    1714                 :     if (!obj)                                                                  \
    1715                 :       return false;                                                            \
    1716                 :     *result = OBJECT_TO_JSVAL(obj);                                            \
    1717                 :     break;                                                                     \
    1718                 :   }
    1719                 : #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
    1720                 :   case TYPE_##name: {                                                          \
    1721                 :     type value = *static_cast<type*>(data);                                    \
    1722                 :     if (!JS_NewNumberValue(cx, double(value), result))                         \
    1723                 :       return false;                                                            \
    1724                 :     break;                                                                     \
    1725                 :   }
    1726                 : #define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
    1727                 :   case TYPE_##name:                                                            \
    1728                 :     /* Convert to an integer. We have no idea what character encoding to */    \
    1729                 :     /* use, if any. */                                                         \
    1730                 :     *result = INT_TO_JSVAL(*static_cast<type*>(data));                         \
    1731                 :     break;
    1732                 : #include "typedefs.h"
    1733                 :   case TYPE_jschar: {
    1734                 :     // Convert the jschar to a 1-character string.
    1735               0 :     JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
    1736               0 :     if (!str)
    1737               0 :       return false;
    1738                 : 
    1739               0 :     *result = STRING_TO_JSVAL(str);
    1740               0 :     break;
    1741                 :   }
    1742                 :   case TYPE_pointer:
    1743                 :   case TYPE_array:
    1744                 :   case TYPE_struct: {
    1745                 :     // We're about to create a new CData object to return. If the caller doesn't
    1746                 :     // want this, return early.
    1747               0 :     if (wantPrimitive) {
    1748               0 :       JS_ReportError(cx, "cannot convert to primitive value");
    1749               0 :       return false;
    1750                 :     }
    1751                 : 
    1752               0 :     JSObject* obj = CData::Create(cx, typeObj, parentObj, data, ownResult);
    1753               0 :     if (!obj)
    1754               0 :       return false;
    1755                 : 
    1756               0 :     *result = OBJECT_TO_JSVAL(obj);
    1757               0 :     break;
    1758                 :   }
    1759                 :   case TYPE_function:
    1760               0 :     JS_NOT_REACHED("cannot return a FunctionType");
    1761                 :   }
    1762                 : 
    1763               0 :   return true;
    1764                 : }
    1765                 : 
    1766                 : // Implicitly convert jsval 'val' to a C binary representation of CType
    1767                 : // 'targetType', storing the result in 'buffer'. Adequate space must be
    1768                 : // provided in 'buffer' by the caller. This function generally does minimal
    1769                 : // coercion between types. There are two cases in which this function is used:
    1770                 : // 1) The target buffer is internal to a CData object; we simply write data
    1771                 : //    into it.
    1772                 : // 2) We are converting an argument for an ffi call, in which case 'isArgument'
    1773                 : //    will be true. This allows us to handle a special case: if necessary,
    1774                 : //    we can autoconvert a JS string primitive to a pointer-to-character type.
    1775                 : //    In this case, ownership of the allocated string is handed off to the
    1776                 : //    caller; 'freePointer' will be set to indicate this.
    1777                 : JSBool
    1778               0 : ImplicitConvert(JSContext* cx,
    1779                 :                 jsval val,
    1780                 :                 JSObject* targetType,
    1781                 :                 void* buffer,
    1782                 :                 bool isArgument,
    1783                 :                 bool* freePointer)
    1784                 : {
    1785               0 :   JS_ASSERT(CType::IsSizeDefined(targetType));
    1786                 : 
    1787                 :   // First, check if val is a CData object of type targetType.
    1788               0 :   JSObject* sourceData = NULL;
    1789               0 :   JSObject* sourceType = NULL;
    1790               0 :   if (!JSVAL_IS_PRIMITIVE(val) &&
    1791               0 :       CData::IsCData(JSVAL_TO_OBJECT(val))) {
    1792               0 :     sourceData = JSVAL_TO_OBJECT(val);
    1793               0 :     sourceType = CData::GetCType(sourceData);
    1794                 : 
    1795                 :     // If the types are equal, copy the buffer contained within the CData.
    1796                 :     // (Note that the buffers may overlap partially or completely.)
    1797               0 :     if (CType::TypesEqual(sourceType, targetType)) {
    1798               0 :       size_t size = CType::GetSize(sourceType);
    1799               0 :       memmove(buffer, CData::GetData(sourceData), size);
    1800               0 :       return true;
    1801                 :     }
    1802                 :   }
    1803                 : 
    1804               0 :   TypeCode targetCode = CType::GetTypeCode(targetType);
    1805                 : 
    1806               0 :   switch (targetCode) {
    1807                 :   case TYPE_bool: {
    1808                 :     // Do not implicitly lose bits, but allow the values 0, 1, and -0.
    1809                 :     // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
    1810                 :     bool result;
    1811               0 :     if (!jsvalToBool(cx, val, &result))
    1812               0 :       return TypeError(cx, "boolean", val);
    1813               0 :     *static_cast<bool*>(buffer) = result;
    1814               0 :     break;
    1815                 :   }
    1816                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    1817                 :   case TYPE_##name: {                                                          \
    1818                 :     /* Do not implicitly lose bits. */                                         \
    1819                 :     type result;                                                               \
    1820                 :     if (!jsvalToInteger(cx, val, &result))                                     \
    1821                 :       return TypeError(cx, #name, val);                                        \
    1822                 :     *static_cast<type*>(buffer) = result;                                      \
    1823                 :     break;                                                                     \
    1824                 :   }
    1825                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    1826                 : #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
    1827                 :   case TYPE_##name: {                                                          \
    1828                 :     type result;                                                               \
    1829                 :     if (!jsvalToFloat(cx, val, &result))                                       \
    1830                 :       return TypeError(cx, #name, val);                                        \
    1831                 :     *static_cast<type*>(buffer) = result;                                      \
    1832                 :     break;                                                                     \
    1833                 :   }
    1834                 : #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    1835                 : #define DEFINE_JSCHAR_TYPE(name, type, ffiType)                                \
    1836                 :   case TYPE_##name: {                                                          \
    1837                 :     /* Convert from a 1-character string, regardless of encoding, */           \
    1838                 :     /* or from an integer, provided the result fits in 'type'. */              \
    1839                 :     type result;                                                               \
    1840                 :     if (JSVAL_IS_STRING(val)) {                                                \
    1841                 :       JSString* str = JSVAL_TO_STRING(val);                                    \
    1842                 :       if (str->length() != 1)                                                  \
    1843                 :         return TypeError(cx, #name, val);                                      \
    1844                 :       const jschar *chars = str->getChars(cx);                                 \
    1845                 :       if (!chars)                                                              \
    1846                 :         return false;                                                          \
    1847                 :       result = chars[0];                                                       \
    1848                 :     } else if (!jsvalToInteger(cx, val, &result)) {                            \
    1849                 :       return TypeError(cx, #name, val);                                        \
    1850                 :     }                                                                          \
    1851                 :     *static_cast<type*>(buffer) = result;                                      \
    1852                 :     break;                                                                     \
    1853                 :   }
    1854                 : #include "typedefs.h"
    1855                 :   case TYPE_pointer: {
    1856               0 :     if (JSVAL_IS_NULL(val)) {
    1857                 :       // Convert to a null pointer.
    1858               0 :       *static_cast<void**>(buffer) = NULL;
    1859               0 :       break;
    1860                 :     }
    1861                 : 
    1862               0 :     JSObject* baseType = PointerType::GetBaseType(targetType);
    1863               0 :     if (sourceData) {
    1864                 :       // First, determine if the targetType is ctypes.void_t.ptr.
    1865               0 :       TypeCode sourceCode = CType::GetTypeCode(sourceType);
    1866               0 :       void* sourceBuffer = CData::GetData(sourceData);
    1867               0 :       bool voidptrTarget = CType::GetTypeCode(baseType) == TYPE_void_t;
    1868                 : 
    1869               0 :       if (sourceCode == TYPE_pointer && voidptrTarget) {
    1870                 :         // Autoconvert if targetType is ctypes.voidptr_t.
    1871               0 :         *static_cast<void**>(buffer) = *static_cast<void**>(sourceBuffer);
    1872               0 :         break;
    1873                 :       }
    1874               0 :       if (sourceCode == TYPE_array) {
    1875                 :         // Autoconvert an array to a ctypes.void_t.ptr or to
    1876                 :         // sourceType.elementType.ptr, just like C.
    1877               0 :         JSObject* elementType = ArrayType::GetBaseType(sourceType);
    1878               0 :         if (voidptrTarget || CType::TypesEqual(baseType, elementType)) {
    1879               0 :           *static_cast<void**>(buffer) = sourceBuffer;
    1880               0 :           break;
    1881                 :         }
    1882                 :       }
    1883                 : 
    1884               0 :     } else if (isArgument && JSVAL_IS_STRING(val)) {
    1885                 :       // Convert the string for the ffi call. This requires allocating space
    1886                 :       // which the caller assumes ownership of.
    1887                 :       // TODO: Extend this so we can safely convert strings at other times also.
    1888               0 :       JSString* sourceString = JSVAL_TO_STRING(val);
    1889               0 :       size_t sourceLength = sourceString->length();
    1890               0 :       const jschar* sourceChars = sourceString->getChars(cx);
    1891               0 :       if (!sourceChars)
    1892               0 :         return false;
    1893                 : 
    1894               0 :       switch (CType::GetTypeCode(baseType)) {
    1895                 :       case TYPE_char:
    1896                 :       case TYPE_signed_char:
    1897                 :       case TYPE_unsigned_char: {
    1898                 :         // Convert from UTF-16 to UTF-8.
    1899                 :         size_t nbytes =
    1900               0 :           GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
    1901               0 :         if (nbytes == (size_t) -1)
    1902               0 :           return false;
    1903                 : 
    1904               0 :         char** charBuffer = static_cast<char**>(buffer);
    1905               0 :         *charBuffer = cx->array_new<char>(nbytes + 1);
    1906               0 :         if (!*charBuffer) {
    1907               0 :           JS_ReportAllocationOverflow(cx);
    1908               0 :           return false;
    1909                 :         }
    1910                 : 
    1911                 :         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
    1912               0 :                     *charBuffer, &nbytes));
    1913               0 :         (*charBuffer)[nbytes] = 0;
    1914               0 :         *freePointer = true;
    1915               0 :         break;
    1916                 :       }
    1917                 :       case TYPE_jschar: {
    1918                 :         // Copy the jschar string data. (We could provide direct access to the
    1919                 :         // JSString's buffer, but this approach is safer if the caller happens
    1920                 :         // to modify the string.)
    1921               0 :         jschar** jscharBuffer = static_cast<jschar**>(buffer);
    1922               0 :         *jscharBuffer = cx->array_new<jschar>(sourceLength + 1);
    1923               0 :         if (!*jscharBuffer) {
    1924               0 :           JS_ReportAllocationOverflow(cx);
    1925               0 :           return false;
    1926                 :         }
    1927                 : 
    1928               0 :         *freePointer = true;
    1929               0 :         memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
    1930               0 :         (*jscharBuffer)[sourceLength] = 0;
    1931               0 :         break;
    1932                 :       }
    1933                 :       default:
    1934               0 :         return TypeError(cx, "pointer", val);
    1935                 :       }
    1936               0 :       break;
    1937                 :     }
    1938               0 :     return TypeError(cx, "pointer", val);
    1939                 :   }
    1940                 :   case TYPE_array: {
    1941               0 :     JSObject* baseType = ArrayType::GetBaseType(targetType);
    1942               0 :     size_t targetLength = ArrayType::GetLength(targetType);
    1943                 : 
    1944               0 :     if (JSVAL_IS_STRING(val)) {
    1945               0 :       JSString* sourceString = JSVAL_TO_STRING(val);
    1946               0 :       size_t sourceLength = sourceString->length();
    1947               0 :       const jschar* sourceChars = sourceString->getChars(cx);
    1948               0 :       if (!sourceChars)
    1949               0 :         return false;
    1950                 : 
    1951               0 :       switch (CType::GetTypeCode(baseType)) {
    1952                 :       case TYPE_char:
    1953                 :       case TYPE_signed_char:
    1954                 :       case TYPE_unsigned_char: {
    1955                 :         // Convert from UTF-16 to UTF-8.
    1956                 :         size_t nbytes =
    1957               0 :           GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
    1958               0 :         if (nbytes == (size_t) -1)
    1959               0 :           return false;
    1960                 : 
    1961               0 :         if (targetLength < nbytes) {
    1962               0 :           JS_ReportError(cx, "ArrayType has insufficient length");
    1963               0 :           return false;
    1964                 :         }
    1965                 : 
    1966               0 :         char* charBuffer = static_cast<char*>(buffer);
    1967                 :         ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
    1968               0 :                     charBuffer, &nbytes));
    1969                 : 
    1970               0 :         if (targetLength > nbytes)
    1971               0 :           charBuffer[nbytes] = 0;
    1972                 : 
    1973               0 :         break;
    1974                 :       }
    1975                 :       case TYPE_jschar: {
    1976                 :         // Copy the string data, jschar for jschar, including the terminator
    1977                 :         // if there's space.
    1978               0 :         if (targetLength < sourceLength) {
    1979               0 :           JS_ReportError(cx, "ArrayType has insufficient length");
    1980               0 :           return false;
    1981                 :         }
    1982                 : 
    1983               0 :         memcpy(buffer, sourceChars, sourceLength * sizeof(jschar));
    1984               0 :         if (targetLength > sourceLength)
    1985               0 :           static_cast<jschar*>(buffer)[sourceLength] = 0;
    1986                 : 
    1987               0 :         break;
    1988                 :       }
    1989                 :       default:
    1990               0 :         return TypeError(cx, "array", val);
    1991                 :       }
    1992                 : 
    1993               0 :     } else if (!JSVAL_IS_PRIMITIVE(val) &&
    1994               0 :                JS_IsArrayObject(cx, JSVAL_TO_OBJECT(val))) {
    1995                 :       // Convert each element of the array by calling ImplicitConvert.
    1996               0 :       JSObject* sourceArray = JSVAL_TO_OBJECT(val);
    1997                 :       uint32_t sourceLength;
    1998               0 :       if (!JS_GetArrayLength(cx, sourceArray, &sourceLength) ||
    1999                 :           targetLength != size_t(sourceLength)) {
    2000               0 :         JS_ReportError(cx, "ArrayType length does not match source array length");
    2001               0 :         return false;
    2002                 :       }
    2003                 : 
    2004                 :       // Convert into an intermediate, in case of failure.
    2005               0 :       size_t elementSize = CType::GetSize(baseType);
    2006               0 :       size_t arraySize = elementSize * targetLength;
    2007               0 :       AutoPtr<char>::Array intermediate(cx->array_new<char>(arraySize));
    2008               0 :       if (!intermediate) {
    2009               0 :         JS_ReportAllocationOverflow(cx);
    2010               0 :         return false;
    2011                 :       }
    2012                 : 
    2013               0 :       for (uint32_t i = 0; i < sourceLength; ++i) {
    2014               0 :         js::AutoValueRooter item(cx);
    2015               0 :         if (!JS_GetElement(cx, sourceArray, i, item.jsval_addr()))
    2016               0 :           return false;
    2017                 : 
    2018               0 :         char* data = intermediate.get() + elementSize * i;
    2019               0 :         if (!ImplicitConvert(cx, item.jsval_value(), baseType, data, false, NULL))
    2020               0 :           return false;
    2021                 :       }
    2022                 : 
    2023               0 :       memcpy(buffer, intermediate.get(), arraySize);
    2024                 : 
    2025                 :     } else {
    2026                 :       // Don't implicitly convert to string. Users can implicitly convert
    2027                 :       // with `String(x)` or `""+x`.
    2028               0 :       return TypeError(cx, "array", val);
    2029                 :     }
    2030               0 :     break;
    2031                 :   }
    2032                 :   case TYPE_struct: {
    2033               0 :     if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) {
    2034                 :       // Enumerate the properties of the object; if they match the struct
    2035                 :       // specification, convert the fields.
    2036               0 :       JSObject* obj = JSVAL_TO_OBJECT(val);
    2037               0 :       JSObject* iter = JS_NewPropertyIterator(cx, obj);
    2038               0 :       if (!iter)
    2039               0 :         return false;
    2040               0 :       js::AutoObjectRooter iterroot(cx, iter);
    2041                 : 
    2042                 :       // Convert into an intermediate, in case of failure.
    2043               0 :       size_t structSize = CType::GetSize(targetType);
    2044               0 :       AutoPtr<char>::Array intermediate(cx->array_new<char>(structSize));
    2045               0 :       if (!intermediate) {
    2046               0 :         JS_ReportAllocationOverflow(cx);
    2047               0 :         return false;
    2048                 :       }
    2049                 : 
    2050                 :       jsid id;
    2051               0 :       size_t i = 0;
    2052               0 :       while (1) {
    2053               0 :         if (!JS_NextProperty(cx, iter, &id))
    2054               0 :           return false;
    2055               0 :         if (JSID_IS_VOID(id))
    2056                 :           break;
    2057                 : 
    2058               0 :         if (!JSID_IS_STRING(id)) {
    2059               0 :           JS_ReportError(cx, "property name is not a string");
    2060               0 :           return false;
    2061                 :         }
    2062                 : 
    2063               0 :         JSFlatString *name = JSID_TO_FLAT_STRING(id);
    2064               0 :         const FieldInfo* field = StructType::LookupField(cx, targetType, name);
    2065               0 :         if (!field)
    2066               0 :           return false;
    2067                 : 
    2068               0 :         js::AutoValueRooter prop(cx);
    2069               0 :         if (!JS_GetPropertyById(cx, obj, id, prop.jsval_addr()))
    2070               0 :           return false;
    2071                 : 
    2072                 :         // Convert the field via ImplicitConvert().
    2073               0 :         char* fieldData = intermediate.get() + field->mOffset;
    2074               0 :         if (!ImplicitConvert(cx, prop.jsval_value(), field->mType, fieldData, false, NULL))
    2075               0 :           return false;
    2076                 : 
    2077               0 :         ++i;
    2078                 :       }
    2079                 : 
    2080               0 :       const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
    2081               0 :       if (i != fields->count()) {
    2082               0 :         JS_ReportError(cx, "missing fields");
    2083               0 :         return false;
    2084                 :       }
    2085                 : 
    2086               0 :       memcpy(buffer, intermediate.get(), structSize);
    2087               0 :       break;
    2088                 :     }
    2089                 : 
    2090               0 :     return TypeError(cx, "struct", val);
    2091                 :   }
    2092                 :   case TYPE_void_t:
    2093                 :   case TYPE_function:
    2094               0 :     JS_NOT_REACHED("invalid type");
    2095                 :     return false;
    2096                 :   }
    2097                 : 
    2098               0 :   return true;
    2099                 : }
    2100                 : 
    2101                 : // Convert jsval 'val' to a C binary representation of CType 'targetType',
    2102                 : // storing the result in 'buffer'. This function is more forceful than
    2103                 : // ImplicitConvert.
    2104                 : JSBool
    2105               0 : ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer)
    2106                 : {
    2107                 :   // If ImplicitConvert succeeds, use that result.
    2108               0 :   if (ImplicitConvert(cx, val, targetType, buffer, false, NULL))
    2109               0 :     return true;
    2110                 : 
    2111                 :   // If ImplicitConvert failed, and there is no pending exception, then assume
    2112                 :   // hard failure (out of memory, or some other similarly serious condition).
    2113                 :   // We store any pending exception in case we need to re-throw it.
    2114               0 :   js::AutoValueRooter ex(cx);
    2115               0 :   if (!JS_GetPendingException(cx, ex.jsval_addr()))
    2116               0 :     return false;
    2117                 : 
    2118                 :   // Otherwise, assume soft failure. Clear the pending exception so that we
    2119                 :   // can throw a different one as required.
    2120               0 :   JS_ClearPendingException(cx);
    2121                 : 
    2122               0 :   TypeCode type = CType::GetTypeCode(targetType);
    2123                 : 
    2124               0 :   switch (type) {
    2125                 :   case TYPE_bool: {
    2126                 :     // Convert according to the ECMAScript ToBoolean() function.
    2127                 :     JSBool result;
    2128               0 :     ASSERT_OK(JS_ValueToBoolean(cx, val, &result));
    2129               0 :     *static_cast<bool*>(buffer) = result != JS_FALSE;
    2130               0 :     break;
    2131                 :   }
    2132                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    2133                 :   case TYPE_##name: {                                                          \
    2134                 :     /* Convert numeric values with a C-style cast, and */                      \
    2135                 :     /* allow conversion from a base-10 or base-16 string. */                   \
    2136                 :     type result;                                                               \
    2137                 :     if (!jsvalToIntegerExplicit(val, &result) &&                               \
    2138                 :         (!JSVAL_IS_STRING(val) ||                                              \
    2139                 :          !StringToInteger(cx, JSVAL_TO_STRING(val), &result)))                 \
    2140                 :       return TypeError(cx, #name, val);                                        \
    2141                 :     *static_cast<type*>(buffer) = result;                                      \
    2142                 :     break;                                                                     \
    2143                 :   }
    2144                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    2145                 : #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    2146                 : #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z)
    2147                 : #include "typedefs.h"
    2148                 :   case TYPE_pointer: {
    2149                 :     // Convert a number, Int64 object, or UInt64 object to a pointer.
    2150                 :     uintptr_t result;
    2151               0 :     if (!jsvalToPtrExplicit(cx, val, &result))
    2152               0 :       return TypeError(cx, "pointer", val);
    2153               0 :     *static_cast<uintptr_t*>(buffer) = result;
    2154               0 :     break;
    2155                 :   }
    2156                 :   case TYPE_float32_t:
    2157                 :   case TYPE_float64_t:
    2158                 :   case TYPE_float:
    2159                 :   case TYPE_double:
    2160                 :   case TYPE_array:
    2161                 :   case TYPE_struct:
    2162                 :     // ImplicitConvert is sufficient. Re-throw the exception it generated.
    2163               0 :     JS_SetPendingException(cx, ex.jsval_value());
    2164               0 :     return false;
    2165                 :   case TYPE_void_t:
    2166                 :   case TYPE_function:
    2167               0 :     JS_NOT_REACHED("invalid type");
    2168                 :     return false;
    2169                 :   }
    2170               0 :   return true;
    2171                 : }
    2172                 : 
    2173                 : // Given a CType 'typeObj', generate a string describing the C type declaration
    2174                 : // corresponding to 'typeObj'. For instance, the CType constructed from
    2175                 : // 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string
    2176                 : // 'int32_t*(**)[4]'.
    2177                 : static JSString*
    2178               0 : BuildTypeName(JSContext* cx, JSObject* typeObj)
    2179                 : {
    2180               0 :   AutoString result;
    2181                 : 
    2182                 :   // Walk the hierarchy of types, outermost to innermost, building up the type
    2183                 :   // string. This consists of the base type, which goes on the left.
    2184                 :   // Derived type modifiers (* and []) build from the inside outward, with
    2185                 :   // pointers on the left and arrays on the right. An excellent description
    2186                 :   // of the rules for building C type declarations can be found at:
    2187                 :   // http://unixwiz.net/techtips/reading-cdecl.html
    2188               0 :   TypeCode prevGrouping = CType::GetTypeCode(typeObj), currentGrouping;
    2189               0 :   while (1) {
    2190               0 :     currentGrouping = CType::GetTypeCode(typeObj);
    2191               0 :     switch (currentGrouping) {
    2192                 :     case TYPE_pointer: {
    2193                 :       // Pointer types go on the left.
    2194               0 :       PrependString(result, "*");
    2195                 : 
    2196               0 :       typeObj = PointerType::GetBaseType(typeObj);
    2197               0 :       prevGrouping = currentGrouping;
    2198               0 :       continue;
    2199                 :     }
    2200                 :     case TYPE_array: {
    2201               0 :       if (prevGrouping == TYPE_pointer) {
    2202                 :         // Outer type is pointer, inner type is array. Grouping is required.
    2203               0 :         PrependString(result, "(");
    2204               0 :         AppendString(result, ")");
    2205                 :       } 
    2206                 : 
    2207                 :       // Array types go on the right.
    2208               0 :       AppendString(result, "[");
    2209                 :       size_t length;
    2210               0 :       if (ArrayType::GetSafeLength(typeObj, &length))
    2211               0 :         IntegerToString(length, 10, result);
    2212                 : 
    2213               0 :       AppendString(result, "]");
    2214                 : 
    2215               0 :       typeObj = ArrayType::GetBaseType(typeObj);
    2216               0 :       prevGrouping = currentGrouping;
    2217               0 :       continue;
    2218                 :     }
    2219                 :     case TYPE_function: {
    2220               0 :       FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    2221                 : 
    2222                 :       // Add in the calling convention, if it's not cdecl.
    2223                 :       // There's no trailing or leading space needed here, as none of the
    2224                 :       // modifiers can produce a string beginning with an identifier ---
    2225                 :       // except for TYPE_function itself, which is fine because functions
    2226                 :       // can't return functions.
    2227               0 :       ABICode abi = GetABICode(fninfo->mABI);
    2228               0 :       if (abi == ABI_STDCALL)
    2229               0 :         PrependString(result, "__stdcall");
    2230               0 :       else if (abi == ABI_WINAPI)
    2231               0 :         PrependString(result, "WINAPI");
    2232                 : 
    2233                 :       // Function application binds more tightly than dereferencing, so
    2234                 :       // wrap pointer types in parens. Functions can't return functions
    2235                 :       // (only pointers to them), and arrays can't hold functions
    2236                 :       // (similarly), so we don't need to address those cases.
    2237               0 :       if (prevGrouping == TYPE_pointer) {
    2238               0 :         PrependString(result, "(");
    2239               0 :         AppendString(result, ")");
    2240                 :       }
    2241                 : 
    2242                 :       // Argument list goes on the right.
    2243               0 :       AppendString(result, "(");
    2244               0 :       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    2245               0 :         JSString* argName = CType::GetName(cx, fninfo->mArgTypes[i]);
    2246               0 :         AppendString(result, argName);
    2247               0 :         if (i != fninfo->mArgTypes.length() - 1 ||
    2248                 :             fninfo->mIsVariadic)
    2249               0 :           AppendString(result, ", ");
    2250                 :       }
    2251               0 :       if (fninfo->mIsVariadic)
    2252               0 :         AppendString(result, "...");
    2253               0 :       AppendString(result, ")");
    2254                 : 
    2255                 :       // Set 'typeObj' to the return type, and let the loop process it.
    2256                 :       // 'prevGrouping' doesn't matter here, because functions cannot return
    2257                 :       // arrays -- thus the parenthetical rules don't get tickled.
    2258               0 :       typeObj = fninfo->mReturnType;
    2259               0 :       continue;
    2260                 :     }
    2261                 :     default:
    2262                 :       // Either a basic or struct type. Use the type's name as the base type.
    2263                 :       break;
    2264                 :     }
    2265                 :     break;
    2266                 :   }
    2267                 : 
    2268                 :   // If prepending the base type name directly would splice two
    2269                 :   // identifiers, insert a space.
    2270               0 :   if (('a' <= result[0] && result[0] <= 'z') ||
    2271               0 :       ('A' <= result[0] && result[0] <= 'Z') ||
    2272               0 :       (result[0] == '_'))
    2273               0 :     PrependString(result, " ");
    2274                 : 
    2275                 :   // Stick the base type and derived type parts together.
    2276               0 :   JSString* baseName = CType::GetName(cx, typeObj);
    2277               0 :   PrependString(result, baseName);
    2278               0 :   return NewUCString(cx, result);
    2279                 : }
    2280                 : 
    2281                 : // Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
    2282                 : // would construct the same CType. If 'makeShort' is true, assume that any
    2283                 : // StructType 't' is bound to an in-scope variable of name 't.name', and use
    2284                 : // that variable in place of generating a string to construct the type 't'.
    2285                 : // (This means the type comparison function CType::TypesEqual will return true
    2286                 : // when comparing the input and output of BuildTypeSource, since struct
    2287                 : // equality is determined by strict JSObject pointer equality.)
    2288                 : static void
    2289               0 : BuildTypeSource(JSContext* cx,
    2290                 :                 JSObject* typeObj, 
    2291                 :                 bool makeShort, 
    2292                 :                 AutoString& result)
    2293                 : {
    2294                 :   // Walk the types, building up the toSource() string.
    2295               0 :   switch (CType::GetTypeCode(typeObj)) {
    2296                 :   case TYPE_void_t:
    2297                 : #define DEFINE_TYPE(name, type, ffiType)  \
    2298                 :   case TYPE_##name:
    2299                 : #include "typedefs.h"
    2300                 :   {
    2301               0 :     AppendString(result, "ctypes.");
    2302               0 :     JSString* nameStr = CType::GetName(cx, typeObj);
    2303               0 :     AppendString(result, nameStr);
    2304               0 :     break;
    2305                 :   }
    2306                 :   case TYPE_pointer: {
    2307               0 :     JSObject* baseType = PointerType::GetBaseType(typeObj);
    2308                 : 
    2309                 :     // Specialcase ctypes.voidptr_t.
    2310               0 :     if (CType::GetTypeCode(baseType) == TYPE_void_t) {
    2311               0 :       AppendString(result, "ctypes.voidptr_t");
    2312               0 :       break;
    2313                 :     }
    2314                 : 
    2315                 :     // Recursively build the source string, and append '.ptr'.
    2316               0 :     BuildTypeSource(cx, baseType, makeShort, result);
    2317               0 :     AppendString(result, ".ptr");
    2318               0 :     break;
    2319                 :   }
    2320                 :   case TYPE_function: {
    2321               0 :     FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    2322                 : 
    2323               0 :     AppendString(result, "ctypes.FunctionType(");
    2324                 : 
    2325               0 :     switch (GetABICode(fninfo->mABI)) {
    2326                 :     case ABI_DEFAULT:
    2327               0 :       AppendString(result, "ctypes.default_abi, ");
    2328               0 :       break;
    2329                 :     case ABI_STDCALL:
    2330               0 :       AppendString(result, "ctypes.stdcall_abi, ");
    2331               0 :       break;
    2332                 :     case ABI_WINAPI:
    2333               0 :       AppendString(result, "ctypes.winapi_abi, ");
    2334               0 :       break;
    2335                 :     case INVALID_ABI:
    2336               0 :       JS_NOT_REACHED("invalid abi");
    2337                 :       break;
    2338                 :     }
    2339                 : 
    2340                 :     // Recursively build the source string describing the function return and
    2341                 :     // argument types.
    2342               0 :     BuildTypeSource(cx, fninfo->mReturnType, true, result);
    2343                 : 
    2344               0 :     if (fninfo->mArgTypes.length() > 0) {
    2345               0 :       AppendString(result, ", [");
    2346               0 :       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    2347               0 :         BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
    2348               0 :         if (i != fninfo->mArgTypes.length() - 1 ||
    2349                 :             fninfo->mIsVariadic)
    2350               0 :           AppendString(result, ", ");
    2351                 :       }
    2352               0 :       if (fninfo->mIsVariadic)
    2353               0 :         AppendString(result, "\"...\"");
    2354               0 :       AppendString(result, "]");
    2355                 :     }
    2356                 : 
    2357               0 :     AppendString(result, ")");
    2358               0 :     break;
    2359                 :   }
    2360                 :   case TYPE_array: {
    2361                 :     // Recursively build the source string, and append '.array(n)',
    2362                 :     // where n is the array length, or the empty string if the array length
    2363                 :     // is undefined.
    2364               0 :     JSObject* baseType = ArrayType::GetBaseType(typeObj);
    2365               0 :     BuildTypeSource(cx, baseType, makeShort, result);
    2366               0 :     AppendString(result, ".array(");
    2367                 : 
    2368                 :     size_t length;
    2369               0 :     if (ArrayType::GetSafeLength(typeObj, &length))
    2370               0 :       IntegerToString(length, 10, result);
    2371                 : 
    2372               0 :     AppendString(result, ")");
    2373               0 :     break;
    2374                 :   }
    2375                 :   case TYPE_struct: {
    2376               0 :     JSString* name = CType::GetName(cx, typeObj);
    2377                 : 
    2378               0 :     if (makeShort) {
    2379                 :       // Shorten the type declaration by assuming that StructType 't' is bound
    2380                 :       // to an in-scope variable of name 't.name'.
    2381               0 :       AppendString(result, name);
    2382               0 :       break;
    2383                 :     }
    2384                 : 
    2385                 :     // Write the full struct declaration.
    2386               0 :     AppendString(result, "ctypes.StructType(\"");
    2387               0 :     AppendString(result, name);
    2388               0 :     AppendString(result, "\"");
    2389                 : 
    2390                 :     // If it's an opaque struct, we're done.
    2391               0 :     if (!CType::IsSizeDefined(typeObj)) {
    2392               0 :       AppendString(result, ")");
    2393               0 :       break;
    2394                 :     }
    2395                 : 
    2396               0 :     AppendString(result, ", [");
    2397                 : 
    2398               0 :     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
    2399               0 :     size_t length = fields->count();
    2400               0 :     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
    2401               0 :     if (!fieldsArray.resize(length))
    2402                 :       break;
    2403                 : 
    2404               0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
    2405               0 :       fieldsArray[r.front().value.mIndex] = &r.front();
    2406                 : 
    2407               0 :     for (size_t i = 0; i < length; ++i) {
    2408               0 :       const FieldInfoHash::Entry* entry = fieldsArray[i];
    2409               0 :       AppendString(result, "{ \"");
    2410               0 :       AppendString(result, entry->key);
    2411               0 :       AppendString(result, "\": ");
    2412               0 :       BuildTypeSource(cx, entry->value.mType, true, result);
    2413               0 :       AppendString(result, " }");
    2414               0 :       if (i != length - 1)
    2415               0 :         AppendString(result, ", ");
    2416                 :     }
    2417                 : 
    2418               0 :     AppendString(result, "])");
    2419                 :     break;
    2420                 :   }
    2421                 :   }
    2422               0 : }
    2423                 : 
    2424                 : // Given a CData object of CType 'typeObj' with binary value 'data', generate a
    2425                 : // string 'result' such that 'eval(result)' would construct a CData object with
    2426                 : // the same CType and containing the same binary value. This assumes that any
    2427                 : // StructType 't' is bound to an in-scope variable of name 't.name'. (This means
    2428                 : // the type comparison function CType::TypesEqual will return true when
    2429                 : // comparing the types, since struct equality is determined by strict JSObject
    2430                 : // pointer equality.) Further, if 'isImplicit' is true, ensure that the
    2431                 : // resulting string can ImplicitConvert successfully if passed to another data
    2432                 : // constructor. (This is important when called recursively, since fields of
    2433                 : // structs and arrays are converted with ImplicitConvert.)
    2434                 : static JSBool
    2435               0 : BuildDataSource(JSContext* cx,
    2436                 :                 JSObject* typeObj, 
    2437                 :                 void* data, 
    2438                 :                 bool isImplicit, 
    2439                 :                 AutoString& result)
    2440                 : {
    2441               0 :   TypeCode type = CType::GetTypeCode(typeObj);
    2442               0 :   switch (type) {
    2443                 :   case TYPE_bool:
    2444               0 :     if (*static_cast<bool*>(data))
    2445               0 :       AppendString(result, "true");
    2446                 :     else
    2447               0 :       AppendString(result, "false");
    2448               0 :     break;
    2449                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    2450                 :   case TYPE_##name:                                                            \
    2451                 :     /* Serialize as a primitive decimal integer. */                            \
    2452                 :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    2453                 :     break;
    2454                 : #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
    2455                 :   case TYPE_##name:                                                            \
    2456                 :     /* Serialize as a wrapped decimal integer. */                              \
    2457                 :     if (!numeric_limits<type>::is_signed)                                      \
    2458                 :       AppendString(result, "ctypes.UInt64(\"");                                \
    2459                 :     else                                                                       \
    2460                 :       AppendString(result, "ctypes.Int64(\"");                                 \
    2461                 :                                                                                \
    2462                 :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    2463                 :     AppendString(result, "\")");                                               \
    2464                 :     break;
    2465                 : #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
    2466                 :   case TYPE_##name: {                                                          \
    2467                 :     /* Serialize as a primitive double. */                                     \
    2468                 :     double fp = *static_cast<type*>(data);                                     \
    2469                 :     ToCStringBuf cbuf;                                                         \
    2470                 :     char* str = NumberToCString(cx, &cbuf, fp);                                \
    2471                 :     if (!str) {                                                                \
    2472                 :       JS_ReportOutOfMemory(cx);                                                \
    2473                 :       return false;                                                            \
    2474                 :     }                                                                          \
    2475                 :                                                                                \
    2476                 :     result.append(str, strlen(str));                                           \
    2477                 :     break;                                                                     \
    2478                 :   }
    2479                 : #define DEFINE_CHAR_TYPE(name, type, ffiType)                                  \
    2480                 :   case TYPE_##name:                                                            \
    2481                 :     /* Serialize as an integer. */                                             \
    2482                 :     IntegerToString(*static_cast<type*>(data), 10, result);                    \
    2483                 :     break;
    2484                 : #include "typedefs.h"
    2485                 :   case TYPE_jschar: {
    2486                 :     // Serialize as a 1-character JS string.
    2487               0 :     JSString* str = JS_NewUCStringCopyN(cx, static_cast<jschar*>(data), 1);
    2488               0 :     if (!str)
    2489               0 :       return false;
    2490                 : 
    2491                 :     // Escape characters, and quote as necessary.
    2492               0 :     JSString* src = JS_ValueToSource(cx, STRING_TO_JSVAL(str));
    2493               0 :     if (!src)
    2494               0 :       return false;
    2495                 : 
    2496               0 :     AppendString(result, src);
    2497               0 :     break;
    2498                 :   }
    2499                 :   case TYPE_pointer:
    2500                 :   case TYPE_function: {
    2501               0 :     if (isImplicit) {
    2502                 :       // The result must be able to ImplicitConvert successfully.
    2503                 :       // Wrap in a type constructor, then serialize for ExplicitConvert.
    2504               0 :       BuildTypeSource(cx, typeObj, true, result);
    2505               0 :       AppendString(result, "(");
    2506                 :     }
    2507                 : 
    2508                 :     // Serialize the pointer value as a wrapped hexadecimal integer.
    2509               0 :     uintptr_t ptr = *static_cast<uintptr_t*>(data);
    2510               0 :     AppendString(result, "ctypes.UInt64(\"0x");
    2511               0 :     IntegerToString(ptr, 16, result);
    2512               0 :     AppendString(result, "\")");
    2513                 : 
    2514               0 :     if (isImplicit)
    2515               0 :       AppendString(result, ")");
    2516                 : 
    2517               0 :     break;
    2518                 :   }
    2519                 :   case TYPE_array: {
    2520                 :     // Serialize each element of the array recursively. Each element must
    2521                 :     // be able to ImplicitConvert successfully.
    2522               0 :     JSObject* baseType = ArrayType::GetBaseType(typeObj);
    2523               0 :     AppendString(result, "[");
    2524                 : 
    2525               0 :     size_t length = ArrayType::GetLength(typeObj);
    2526               0 :     size_t elementSize = CType::GetSize(baseType);
    2527               0 :     for (size_t i = 0; i < length; ++i) {
    2528               0 :       char* element = static_cast<char*>(data) + elementSize * i;
    2529               0 :       if (!BuildDataSource(cx, baseType, element, true, result))
    2530               0 :         return false;
    2531                 : 
    2532               0 :       if (i + 1 < length)
    2533               0 :         AppendString(result, ", ");
    2534                 :     }
    2535               0 :     AppendString(result, "]");
    2536               0 :     break;
    2537                 :   }
    2538                 :   case TYPE_struct: {
    2539               0 :     if (isImplicit) {
    2540                 :       // The result must be able to ImplicitConvert successfully.
    2541                 :       // Serialize the data as an object with properties, rather than
    2542                 :       // a sequence of arguments to the StructType constructor.
    2543               0 :       AppendString(result, "{");
    2544                 :     }
    2545                 : 
    2546                 :     // Serialize each field of the struct recursively. Each field must
    2547                 :     // be able to ImplicitConvert successfully.
    2548               0 :     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
    2549               0 :     size_t length = fields->count();
    2550               0 :     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
    2551               0 :     if (!fieldsArray.resize(length))
    2552               0 :       return false;
    2553                 : 
    2554               0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
    2555               0 :       fieldsArray[r.front().value.mIndex] = &r.front();
    2556                 : 
    2557               0 :     for (size_t i = 0; i < length; ++i) {
    2558               0 :       const FieldInfoHash::Entry* entry = fieldsArray[i];
    2559                 : 
    2560               0 :       if (isImplicit) {
    2561               0 :         AppendString(result, "\"");
    2562               0 :         AppendString(result, entry->key);
    2563               0 :         AppendString(result, "\": ");
    2564                 :       }
    2565                 : 
    2566               0 :       char* fieldData = static_cast<char*>(data) + entry->value.mOffset;
    2567               0 :       if (!BuildDataSource(cx, entry->value.mType, fieldData, true, result))
    2568               0 :         return false;
    2569                 : 
    2570               0 :       if (i + 1 != length)
    2571               0 :         AppendString(result, ", ");
    2572                 :     }
    2573                 : 
    2574               0 :     if (isImplicit)
    2575               0 :       AppendString(result, "}");
    2576                 : 
    2577               0 :     break;
    2578                 :   }
    2579                 :   case TYPE_void_t:
    2580               0 :     JS_NOT_REACHED("invalid type");
    2581                 :     break;
    2582                 :   }
    2583                 : 
    2584               0 :   return true;
    2585                 : }
    2586                 : 
    2587                 : /*******************************************************************************
    2588                 : ** JSAPI callback function implementations
    2589                 : *******************************************************************************/
    2590                 : 
    2591                 : JSBool
    2592               0 : ConstructAbstract(JSContext* cx,
    2593                 :                   unsigned argc,
    2594                 :                   jsval* vp)
    2595                 : {
    2596                 :   // Calling an abstract base class constructor is disallowed.
    2597               0 :   JS_ReportError(cx, "cannot construct from abstract type");
    2598               0 :   return JS_FALSE;
    2599                 : }
    2600                 : 
    2601                 : /*******************************************************************************
    2602                 : ** CType implementation
    2603                 : *******************************************************************************/
    2604                 : 
    2605                 : JSBool
    2606               0 : CType::ConstructData(JSContext* cx,
    2607                 :                      unsigned argc,
    2608                 :                      jsval* vp)
    2609                 : {
    2610                 :   // get the callee object...
    2611               0 :   JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
    2612               0 :   if (!CType::IsCType(obj)) {
    2613               0 :     JS_ReportError(cx, "not a CType");
    2614               0 :     return JS_FALSE;
    2615                 :   }
    2616                 : 
    2617                 :   // How we construct the CData object depends on what type we represent.
    2618                 :   // An instance 'd' of a CData object of type 't' has:
    2619                 :   //   * [[Class]] "CData"
    2620                 :   //   * __proto__ === t.prototype
    2621               0 :   switch (GetTypeCode(obj)) {
    2622                 :   case TYPE_void_t:
    2623               0 :     JS_ReportError(cx, "cannot construct from void_t");
    2624               0 :     return JS_FALSE;
    2625                 :   case TYPE_function:
    2626               0 :     JS_ReportError(cx, "cannot construct from FunctionType; use FunctionType.ptr instead");
    2627               0 :     return JS_FALSE;
    2628                 :   case TYPE_pointer:
    2629               0 :     return PointerType::ConstructData(cx, obj, argc, vp);
    2630                 :   case TYPE_array:
    2631               0 :     return ArrayType::ConstructData(cx, obj, argc, vp);
    2632                 :   case TYPE_struct:
    2633               0 :     return StructType::ConstructData(cx, obj, argc, vp);
    2634                 :   default:
    2635               0 :     return ConstructBasic(cx, obj, argc, vp);
    2636                 :   }
    2637                 : }
    2638                 : 
    2639                 : JSBool
    2640               0 : CType::ConstructBasic(JSContext* cx,
    2641                 :                       JSObject* obj,
    2642                 :                       unsigned argc,
    2643                 :                       jsval* vp)
    2644                 : {
    2645               0 :   if (argc > 1) {
    2646               0 :     JS_ReportError(cx, "CType constructor takes zero or one argument");
    2647               0 :     return JS_FALSE;
    2648                 :   }
    2649                 : 
    2650                 :   // construct a CData object
    2651               0 :   JSObject* result = CData::Create(cx, obj, NULL, NULL, true);
    2652               0 :   if (!result)
    2653               0 :     return JS_FALSE;
    2654                 : 
    2655               0 :   if (argc == 1) {
    2656               0 :     if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(result)))
    2657               0 :       return JS_FALSE;
    2658                 :   }
    2659                 : 
    2660               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    2661               0 :   return JS_TRUE;
    2662                 : }
    2663                 : 
    2664                 : JSObject*
    2665          723168 : CType::Create(JSContext* cx,
    2666                 :               JSObject* typeProto,
    2667                 :               JSObject* dataProto,
    2668                 :               TypeCode type,
    2669                 :               JSString* name,
    2670                 :               jsval size,
    2671                 :               jsval align,
    2672                 :               ffi_type* ffiType)
    2673                 : {
    2674          723168 :   JSObject* parent = JS_GetParent(typeProto);
    2675          723168 :   JS_ASSERT(parent);
    2676                 : 
    2677                 :   // Create a CType object with the properties and slots common to all CTypes.
    2678                 :   // Each type object 't' has:
    2679                 :   //   * [[Class]] "CType"
    2680                 :   //   * __proto__ === 'typeProto'; one of ctypes.{CType,PointerType,ArrayType,
    2681                 :   //     StructType}.prototype
    2682                 :   //   * A constructor which creates and returns a CData object, containing
    2683                 :   //     binary data of the given type.
    2684                 :   //   * 'prototype' property:
    2685                 :   //     * [[Class]] "CDataProto"
    2686                 :   //     * __proto__ === 'dataProto'; an object containing properties and
    2687                 :   //       functions common to all CData objects of types derived from
    2688                 :   //       'typeProto'. (For instance, this could be ctypes.CData.prototype
    2689                 :   //       for simple types, or something representing structs for StructTypes.)
    2690                 :   //     * 'constructor' property === 't'
    2691                 :   //     * Additional properties specified by 'ps', as appropriate for the
    2692                 :   //       specific type instance 't'.
    2693          723168 :   JSObject* typeObj = JS_NewObject(cx, &sCTypeClass, typeProto, parent);
    2694          723168 :   if (!typeObj)
    2695               0 :     return NULL;
    2696         1446336 :   js::AutoObjectRooter root(cx, typeObj);
    2697                 : 
    2698                 :   // Set up the reserved slots.
    2699          723168 :   JS_SetReservedSlot(typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type));
    2700          723168 :   if (ffiType)
    2701          723168 :     JS_SetReservedSlot(typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType));
    2702          723168 :   if (name)
    2703          699840 :     JS_SetReservedSlot(typeObj, SLOT_NAME, STRING_TO_JSVAL(name));
    2704          723168 :   JS_SetReservedSlot(typeObj, SLOT_SIZE, size);
    2705          723168 :   JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
    2706                 : 
    2707          723168 :   if (dataProto) {
    2708                 :     // Set up the 'prototype' and 'prototype.constructor' properties.
    2709          723168 :     JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, parent);
    2710          723168 :     if (!prototype)
    2711               0 :       return NULL;
    2712         1446336 :     js::AutoObjectRooter protoroot(cx, prototype);
    2713                 : 
    2714          723168 :     if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj),
    2715          723168 :            NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT))
    2716               0 :       return NULL;
    2717                 : 
    2718                 :     // Set the 'prototype' object.
    2719                 :     //if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
    2720                 :     //  return NULL;
    2721         1446336 :     JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
    2722                 :   }
    2723                 : 
    2724          723168 :   if (!JS_FreezeObject(cx, typeObj))
    2725               0 :     return NULL;
    2726                 : 
    2727                 :   // Assert a sanity check on size and alignment: size % alignment should always
    2728                 :   // be zero.
    2729         1423008 :   JS_ASSERT_IF(IsSizeDefined(typeObj),
    2730         1423008 :                GetSize(typeObj) % GetAlignment(typeObj) == 0);
    2731                 : 
    2732          723168 :   return typeObj;
    2733                 : }
    2734                 : 
    2735                 : JSObject*
    2736          699840 : CType::DefineBuiltin(JSContext* cx,
    2737                 :                      JSObject* parent,
    2738                 :                      const char* propName,
    2739                 :                      JSObject* typeProto,
    2740                 :                      JSObject* dataProto,
    2741                 :                      const char* name,
    2742                 :                      TypeCode type,
    2743                 :                      jsval size,
    2744                 :                      jsval align,
    2745                 :                      ffi_type* ffiType)
    2746                 : {
    2747          699840 :   JSString* nameStr = JS_NewStringCopyZ(cx, name);
    2748          699840 :   if (!nameStr)
    2749               0 :     return NULL;
    2750         1399680 :   js::AutoStringRooter nameRoot(cx, nameStr);
    2751                 : 
    2752                 :   // Create a new CType object with the common properties and slots.
    2753                 :   JSObject* typeObj = Create(cx, typeProto, dataProto, type, nameStr, size,
    2754          699840 :                         align, ffiType);
    2755          699840 :   if (!typeObj)
    2756               0 :     return NULL;
    2757                 : 
    2758                 :   // Define the CType as a 'propName' property on 'parent'.
    2759          699840 :   if (!JS_DefineProperty(cx, parent, propName, OBJECT_TO_JSVAL(typeObj),
    2760          699840 :          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    2761               0 :     return NULL;
    2762                 : 
    2763          699840 :   return typeObj;
    2764                 : }
    2765                 : 
    2766                 : void
    2767          723168 : CType::Finalize(JSFreeOp *fop, JSObject* obj)
    2768                 : {
    2769                 :   // Make sure our TypeCode slot is legit. If it's not, bail.
    2770          723168 :   jsval slot = JS_GetReservedSlot(obj, SLOT_TYPECODE);
    2771          723168 :   if (JSVAL_IS_VOID(slot))
    2772               0 :     return;
    2773                 : 
    2774                 :   // The contents of our slots depends on what kind of type we are.
    2775          723168 :   switch (TypeCode(JSVAL_TO_INT(slot))) {
    2776                 :   case TYPE_function: {
    2777                 :     // Free the FunctionInfo.
    2778               0 :     slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
    2779               0 :     if (!JSVAL_IS_VOID(slot))
    2780               0 :       FreeOp::get(fop)->delete_(static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot)));
    2781               0 :     break;
    2782                 :   }
    2783                 : 
    2784                 :   case TYPE_struct: {
    2785                 :     // Free the FieldInfoHash table.
    2786               0 :     slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
    2787               0 :     if (!JSVAL_IS_VOID(slot)) {
    2788               0 :       void* info = JSVAL_TO_PRIVATE(slot);
    2789               0 :       FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
    2790                 :     }
    2791                 :   }
    2792                 : 
    2793                 :     // Fall through.
    2794                 :   case TYPE_array: {
    2795                 :     // Free the ffi_type info.
    2796               0 :     slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
    2797               0 :     if (!JSVAL_IS_VOID(slot)) {
    2798               0 :       ffi_type* ffiType = static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
    2799               0 :       FreeOp::get(fop)->array_delete(ffiType->elements);
    2800               0 :       FreeOp::get(fop)->delete_(ffiType);
    2801                 :     }
    2802                 : 
    2803               0 :     break;
    2804                 :   }
    2805                 :   default:
    2806                 :     // Nothing to do here.
    2807          723168 :     break;
    2808                 :   }
    2809                 : }
    2810                 : 
    2811                 : void
    2812          116640 : CType::FinalizeProtoClass(JSFreeOp *fop, JSObject* obj)
    2813                 : {
    2814                 :   // Finalize the CTypeProto class. The only important bit here is our
    2815                 :   // SLOT_CLOSURECX -- it contains the JSContext that was (lazily) instantiated
    2816                 :   // for use with FunctionType closures. And if we're here, in this finalizer,
    2817                 :   // we're guaranteed to not need it anymore. Note that this slot will only
    2818                 :   // be set for the object (of class CTypeProto) ctypes.FunctionType.prototype.
    2819          116640 :   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSURECX);
    2820          116640 :   if (JSVAL_IS_VOID(slot))
    2821          116640 :     return;
    2822                 : 
    2823               0 :   JSContext* closureCx = static_cast<JSContext*>(JSVAL_TO_PRIVATE(slot));
    2824               0 :   JS_DestroyContextNoGC(closureCx);
    2825                 : }
    2826                 : 
    2827                 : void
    2828         1495554 : CType::Trace(JSTracer* trc, JSObject* obj)
    2829                 : {
    2830                 :   // Make sure our TypeCode slot is legit. If it's not, bail.
    2831         1495554 :   jsval slot = obj->getSlot(SLOT_TYPECODE);
    2832         1495554 :   if (JSVAL_IS_VOID(slot))
    2833               0 :     return;
    2834                 : 
    2835                 :   // The contents of our slots depends on what kind of type we are.
    2836         1495554 :   switch (TypeCode(JSVAL_TO_INT(slot))) {
    2837                 :   case TYPE_struct: {
    2838               0 :     slot = obj->getReservedSlot(SLOT_FIELDINFO);
    2839               0 :     if (JSVAL_IS_VOID(slot))
    2840               0 :       return;
    2841                 : 
    2842                 :     FieldInfoHash* fields =
    2843               0 :       static_cast<FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
    2844               0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    2845               0 :       JS_CALL_TRACER(trc, r.front().key, JSTRACE_STRING, "fieldName");
    2846               0 :       JS_CALL_TRACER(trc, r.front().value.mType, JSTRACE_OBJECT, "fieldType");
    2847                 :     }
    2848                 : 
    2849               0 :     break;
    2850                 :   }
    2851                 :   case TYPE_function: {
    2852                 :     // Check if we have a FunctionInfo.
    2853               0 :     slot = obj->getReservedSlot(SLOT_FNINFO);
    2854               0 :     if (JSVAL_IS_VOID(slot))
    2855               0 :       return;
    2856                 : 
    2857               0 :     FunctionInfo* fninfo = static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
    2858               0 :     JS_ASSERT(fninfo);
    2859                 : 
    2860                 :     // Identify our objects to the tracer.
    2861               0 :     JS_CALL_TRACER(trc, fninfo->mABI, JSTRACE_OBJECT, "abi");
    2862               0 :     JS_CALL_TRACER(trc, fninfo->mReturnType, JSTRACE_OBJECT, "returnType");
    2863               0 :     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i)
    2864               0 :       JS_CALL_TRACER(trc, fninfo->mArgTypes[i], JSTRACE_OBJECT, "argType");
    2865                 : 
    2866               0 :     break;
    2867                 :   }
    2868                 :   default:
    2869                 :     // Nothing to do here.
    2870         1495554 :     break;
    2871                 :   }
    2872                 : }
    2873                 : 
    2874                 : bool
    2875         2192832 : CType::IsCType(JSObject* obj)
    2876                 : {
    2877         2192832 :   return JS_GetClass(obj) == &sCTypeClass;
    2878                 : }
    2879                 : 
    2880                 : bool
    2881           46656 : CType::IsCTypeProto(JSObject* obj)
    2882                 : {
    2883           46656 :   return JS_GetClass(obj) == &sCTypeProtoClass;
    2884                 : }
    2885                 : 
    2886                 : TypeCode
    2887           23328 : CType::GetTypeCode(JSObject* typeObj)
    2888                 : {
    2889           23328 :   JS_ASSERT(IsCType(typeObj));
    2890                 : 
    2891           23328 :   jsval result = JS_GetReservedSlot(typeObj, SLOT_TYPECODE);
    2892           23328 :   return TypeCode(JSVAL_TO_INT(result));
    2893                 : }
    2894                 : 
    2895                 : bool
    2896               0 : CType::TypesEqual(JSObject* t1, JSObject* t2)
    2897                 : {
    2898               0 :   JS_ASSERT(IsCType(t1) && IsCType(t2));
    2899                 : 
    2900                 :   // Fast path: check for object equality.
    2901               0 :   if (t1 == t2)
    2902               0 :     return true;
    2903                 : 
    2904                 :   // First, perform shallow comparison.
    2905               0 :   TypeCode c1 = GetTypeCode(t1);
    2906               0 :   TypeCode c2 = GetTypeCode(t2);
    2907               0 :   if (c1 != c2)
    2908               0 :     return false;
    2909                 : 
    2910                 :   // Determine whether the types require shallow or deep comparison.
    2911               0 :   switch (c1) {
    2912                 :   case TYPE_pointer: {
    2913                 :     // Compare base types.
    2914               0 :     JSObject* b1 = PointerType::GetBaseType(t1);
    2915               0 :     JSObject* b2 = PointerType::GetBaseType(t2);
    2916               0 :     return TypesEqual(b1, b2);
    2917                 :   }
    2918                 :   case TYPE_function: {
    2919               0 :     FunctionInfo* f1 = FunctionType::GetFunctionInfo(t1);
    2920               0 :     FunctionInfo* f2 = FunctionType::GetFunctionInfo(t2);
    2921                 : 
    2922                 :     // Compare abi, return type, and argument types.
    2923               0 :     if (f1->mABI != f2->mABI)
    2924               0 :       return false;
    2925                 : 
    2926               0 :     if (!TypesEqual(f1->mReturnType, f2->mReturnType))
    2927               0 :       return false;
    2928                 : 
    2929               0 :     if (f1->mArgTypes.length() != f2->mArgTypes.length())
    2930               0 :       return false;
    2931                 : 
    2932               0 :     if (f1->mIsVariadic != f2->mIsVariadic)
    2933               0 :       return false;
    2934                 : 
    2935               0 :     for (size_t i = 0; i < f1->mArgTypes.length(); ++i) {
    2936               0 :       if (!TypesEqual(f1->mArgTypes[i], f2->mArgTypes[i]))
    2937               0 :         return false;
    2938                 :     }
    2939                 : 
    2940               0 :     return true;
    2941                 :   }
    2942                 :   case TYPE_array: {
    2943                 :     // Compare length, then base types.
    2944                 :     // An undefined length array matches other undefined length arrays.
    2945               0 :     size_t s1 = 0, s2 = 0;
    2946               0 :     bool d1 = ArrayType::GetSafeLength(t1, &s1);
    2947               0 :     bool d2 = ArrayType::GetSafeLength(t2, &s2);
    2948               0 :     if (d1 != d2 || (d1 && s1 != s2))
    2949               0 :       return false;
    2950                 : 
    2951               0 :     JSObject* b1 = ArrayType::GetBaseType(t1);
    2952               0 :     JSObject* b2 = ArrayType::GetBaseType(t2);
    2953               0 :     return TypesEqual(b1, b2);
    2954                 :   }
    2955                 :   case TYPE_struct:
    2956                 :     // Require exact type object equality.
    2957               0 :     return false;
    2958                 :   default:
    2959                 :     // Shallow comparison is sufficient.
    2960               0 :     return true;
    2961                 :   }
    2962                 : }
    2963                 : 
    2964                 : bool
    2965               0 : CType::GetSafeSize(JSObject* obj, size_t* result)
    2966                 : {
    2967               0 :   JS_ASSERT(CType::IsCType(obj));
    2968                 : 
    2969               0 :   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
    2970                 : 
    2971                 :   // The "size" property can be an int, a double, or JSVAL_VOID
    2972                 :   // (for arrays of undefined length), and must always fit in a size_t.
    2973               0 :   if (JSVAL_IS_INT(size)) {
    2974               0 :     *result = JSVAL_TO_INT(size);
    2975               0 :     return true;
    2976                 :   }
    2977               0 :   if (JSVAL_IS_DOUBLE(size)) {
    2978               0 :     *result = Convert<size_t>(JSVAL_TO_DOUBLE(size));
    2979               0 :     return true;
    2980                 :   }
    2981                 : 
    2982               0 :   JS_ASSERT(JSVAL_IS_VOID(size));
    2983               0 :   return false;
    2984                 : }
    2985                 : 
    2986                 : size_t
    2987          699840 : CType::GetSize(JSObject* obj)
    2988                 : {
    2989          699840 :   JS_ASSERT(CType::IsCType(obj));
    2990                 : 
    2991          699840 :   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
    2992                 : 
    2993          699840 :   JS_ASSERT(!JSVAL_IS_VOID(size));
    2994                 : 
    2995                 :   // The "size" property can be an int, a double, or JSVAL_VOID
    2996                 :   // (for arrays of undefined length), and must always fit in a size_t.
    2997                 :   // For callers who know it can never be JSVAL_VOID, return a size_t directly.
    2998          699840 :   if (JSVAL_IS_INT(size))
    2999          699840 :     return JSVAL_TO_INT(size);
    3000               0 :   return Convert<size_t>(JSVAL_TO_DOUBLE(size));
    3001                 : }
    3002                 : 
    3003                 : bool
    3004          723168 : CType::IsSizeDefined(JSObject* obj)
    3005                 : {
    3006          723168 :   JS_ASSERT(CType::IsCType(obj));
    3007                 : 
    3008          723168 :   jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
    3009                 : 
    3010                 :   // The "size" property can be an int, a double, or JSVAL_VOID
    3011                 :   // (for arrays of undefined length), and must always fit in a size_t.
    3012          723168 :   JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
    3013          723168 :   return !JSVAL_IS_VOID(size);
    3014                 : }
    3015                 : 
    3016                 : size_t
    3017          699840 : CType::GetAlignment(JSObject* obj)
    3018                 : {
    3019          699840 :   JS_ASSERT(CType::IsCType(obj));
    3020                 : 
    3021          699840 :   jsval slot = JS_GetReservedSlot(obj, SLOT_ALIGN);
    3022          699840 :   return static_cast<size_t>(JSVAL_TO_INT(slot));
    3023                 : }
    3024                 : 
    3025                 : ffi_type*
    3026               0 : CType::GetFFIType(JSContext* cx, JSObject* obj)
    3027                 : {
    3028               0 :   JS_ASSERT(CType::IsCType(obj));
    3029                 : 
    3030               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
    3031                 : 
    3032               0 :   if (!JSVAL_IS_VOID(slot)) {
    3033               0 :     return static_cast<ffi_type*>(JSVAL_TO_PRIVATE(slot));
    3034                 :   }
    3035                 : 
    3036               0 :   AutoPtr<ffi_type> result;
    3037               0 :   switch (CType::GetTypeCode(obj)) {
    3038                 :   case TYPE_array:
    3039               0 :     result = ArrayType::BuildFFIType(cx, obj);
    3040               0 :     break;
    3041                 : 
    3042                 :   case TYPE_struct:
    3043               0 :     result = StructType::BuildFFIType(cx, obj);
    3044               0 :     break;
    3045                 : 
    3046                 :   default:
    3047               0 :     JS_NOT_REACHED("simple types must have an ffi_type");
    3048                 :   }
    3049                 : 
    3050               0 :   if (!result)
    3051               0 :     return NULL;
    3052               0 :   JS_SetReservedSlot(obj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(result.get()));
    3053               0 :   return result.forget();
    3054                 : }
    3055                 : 
    3056                 : JSString*
    3057               0 : CType::GetName(JSContext* cx, JSObject* obj)
    3058                 : {
    3059               0 :   JS_ASSERT(CType::IsCType(obj));
    3060                 : 
    3061               0 :   jsval string = JS_GetReservedSlot(obj, SLOT_NAME);
    3062               0 :   if (JSVAL_IS_VOID(string)) {
    3063                 :     // Build the type name lazily.
    3064               0 :     JSString* name = BuildTypeName(cx, obj);
    3065               0 :     if (!name)
    3066               0 :       return NULL;
    3067               0 :     JS_SetReservedSlot(obj, SLOT_NAME, STRING_TO_JSVAL(name));
    3068               0 :     return name;
    3069                 :   }
    3070                 : 
    3071               0 :   return JSVAL_TO_STRING(string);
    3072                 : }
    3073                 : 
    3074                 : JSObject*
    3075               0 : CType::GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot)
    3076                 : {
    3077                 :   // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot
    3078                 :   // on the type constructor.
    3079               0 :   jsval protoslot = js::GetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO);
    3080               0 :   JSObject* proto = JSVAL_TO_OBJECT(protoslot);
    3081               0 :   JS_ASSERT(proto);
    3082               0 :   JS_ASSERT(CType::IsCTypeProto(proto));
    3083                 : 
    3084                 :   // Get the desired prototype.
    3085               0 :   jsval result = JS_GetReservedSlot(proto, slot);
    3086               0 :   return JSVAL_TO_OBJECT(result);
    3087                 : }
    3088                 : 
    3089                 : JSObject*
    3090           46656 : CType::GetProtoFromType(JSObject* obj, CTypeProtoSlot slot)
    3091                 : {
    3092           46656 :   JS_ASSERT(IsCType(obj));
    3093                 : 
    3094                 :   // Get the prototype of the type object.
    3095           46656 :   JSObject* proto = JS_GetPrototype(obj);
    3096           46656 :   JS_ASSERT(proto);
    3097           46656 :   JS_ASSERT(CType::IsCTypeProto(proto));
    3098                 : 
    3099                 :   // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype.
    3100           46656 :   jsval result = JS_GetReservedSlot(proto, slot);
    3101           46656 :   return JSVAL_TO_OBJECT(result);
    3102                 : }
    3103                 : 
    3104                 : JSBool
    3105               0 : CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3106                 : {
    3107               0 :   if (!(CType::IsCType(obj) || CType::IsCTypeProto(obj))) {
    3108               0 :     JS_ReportError(cx, "not a CType or CTypeProto");
    3109               0 :     return JS_FALSE;
    3110                 :   }
    3111                 : 
    3112               0 :   unsigned slot = CType::IsCTypeProto(obj) ? (unsigned) SLOT_OURDATAPROTO
    3113               0 :                                            : (unsigned) SLOT_PROTO;
    3114               0 :   *vp = JS_GetReservedSlot(obj, slot);
    3115               0 :   JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp) || JSVAL_IS_VOID(*vp));
    3116               0 :   return JS_TRUE;
    3117                 : }
    3118                 : 
    3119                 : JSBool
    3120               0 : CType::NameGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3121                 : {
    3122               0 :   if (!CType::IsCType(obj)) {
    3123               0 :     JS_ReportError(cx, "not a CType");
    3124               0 :     return JS_FALSE;
    3125                 :   }
    3126                 : 
    3127               0 :   JSString* name = CType::GetName(cx, obj);
    3128               0 :   if (!name)
    3129               0 :     return JS_FALSE;
    3130                 : 
    3131               0 :   *vp = STRING_TO_JSVAL(name);
    3132               0 :   return JS_TRUE;
    3133                 : }
    3134                 : 
    3135                 : JSBool
    3136               0 : CType::SizeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3137                 : {
    3138               0 :   if (!CType::IsCType(obj)) {
    3139               0 :     JS_ReportError(cx, "not a CType");
    3140               0 :     return JS_FALSE;
    3141                 :   }
    3142                 : 
    3143               0 :   *vp = JS_GetReservedSlot(obj, SLOT_SIZE);
    3144               0 :   JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp));
    3145               0 :   return JS_TRUE;
    3146                 : }
    3147                 : 
    3148                 : JSBool
    3149               0 : CType::PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3150                 : {
    3151               0 :   if (!CType::IsCType(obj)) {
    3152               0 :     JS_ReportError(cx, "not a CType");
    3153               0 :     return JS_FALSE;
    3154                 :   }
    3155                 : 
    3156               0 :   JSObject* pointerType = PointerType::CreateInternal(cx, obj);
    3157               0 :   if (!pointerType)
    3158               0 :     return JS_FALSE;
    3159                 : 
    3160               0 :   *vp = OBJECT_TO_JSVAL(pointerType);
    3161               0 :   return JS_TRUE;
    3162                 : }
    3163                 : 
    3164                 : JSBool
    3165               0 : CType::CreateArray(JSContext* cx, unsigned argc, jsval* vp)
    3166                 : {
    3167               0 :   JSObject* baseType = JS_THIS_OBJECT(cx, vp);
    3168               0 :   if (!baseType || !CType::IsCType(baseType)) {
    3169               0 :     JS_ReportError(cx, "not a CType");
    3170               0 :     return JS_FALSE;
    3171                 :   }
    3172                 : 
    3173                 :   // Construct and return a new ArrayType object.
    3174               0 :   if (argc > 1) {
    3175               0 :     JS_ReportError(cx, "array takes zero or one argument");
    3176               0 :     return JS_FALSE;
    3177                 :   }
    3178                 : 
    3179                 :   // Convert the length argument to a size_t.
    3180               0 :   jsval* argv = JS_ARGV(cx, vp);
    3181               0 :   size_t length = 0;
    3182               0 :   if (argc == 1 && !jsvalToSize(cx, argv[0], false, &length)) {
    3183               0 :     JS_ReportError(cx, "argument must be a nonnegative integer");
    3184               0 :     return JS_FALSE;
    3185                 :   }
    3186                 : 
    3187               0 :   JSObject* result = ArrayType::CreateInternal(cx, baseType, length, argc == 1);
    3188               0 :   if (!result)
    3189               0 :     return JS_FALSE;
    3190                 : 
    3191               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3192               0 :   return JS_TRUE;
    3193                 : }
    3194                 : 
    3195                 : JSBool
    3196               0 : CType::ToString(JSContext* cx, unsigned argc, jsval* vp)
    3197                 : {
    3198               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    3199               0 :   if (!obj || !(CType::IsCType(obj) || CType::IsCTypeProto(obj))) {
    3200               0 :     JS_ReportError(cx, "not a CType");
    3201               0 :     return JS_FALSE;
    3202                 :   }
    3203                 : 
    3204                 :   // Create the appropriate string depending on whether we're sCTypeClass or
    3205                 :   // sCTypeProtoClass.
    3206                 :   JSString* result;
    3207               0 :   if (CType::IsCType(obj)) {
    3208               0 :     AutoString type;
    3209               0 :     AppendString(type, "type ");
    3210               0 :     AppendString(type, GetName(cx, obj));
    3211               0 :     result = NewUCString(cx, type);
    3212                 :   }
    3213                 :   else {
    3214               0 :     result = JS_NewStringCopyZ(cx, "[CType proto object]");
    3215                 :   }
    3216               0 :   if (!result)
    3217               0 :     return JS_FALSE;
    3218                 : 
    3219               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    3220               0 :   return JS_TRUE;
    3221                 : }
    3222                 : 
    3223                 : JSBool
    3224               0 : CType::ToSource(JSContext* cx, unsigned argc, jsval* vp)
    3225                 : {
    3226               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    3227               0 :   if (!obj ||
    3228               0 :       !(CType::IsCType(obj) || CType::IsCTypeProto(obj)))
    3229                 :   {
    3230               0 :     JS_ReportError(cx, "not a CType");
    3231               0 :     return JS_FALSE;
    3232                 :   }
    3233                 : 
    3234                 :   // Create the appropriate string depending on whether we're sCTypeClass or
    3235                 :   // sCTypeProtoClass.
    3236                 :   JSString* result;
    3237               0 :   if (CType::IsCType(obj)) {
    3238               0 :     AutoString source;
    3239               0 :     BuildTypeSource(cx, obj, false, source);
    3240               0 :     result = NewUCString(cx, source);
    3241                 :   } else {
    3242               0 :     result = JS_NewStringCopyZ(cx, "[CType proto object]");
    3243                 :   }
    3244               0 :   if (!result)
    3245               0 :     return JS_FALSE;
    3246                 : 
    3247               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    3248               0 :   return JS_TRUE;
    3249                 : }
    3250                 : 
    3251                 : JSBool
    3252               0 : CType::HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp)
    3253                 : {
    3254               0 :   JS_ASSERT(CType::IsCType(obj));
    3255                 : 
    3256               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO);
    3257               0 :   JSObject* prototype = JSVAL_TO_OBJECT(slot);
    3258               0 :   JS_ASSERT(prototype);
    3259               0 :   JS_ASSERT(CData::IsCDataProto(prototype));
    3260                 : 
    3261               0 :   *bp = JS_FALSE;
    3262               0 :   if (JSVAL_IS_PRIMITIVE(*v))
    3263               0 :     return JS_TRUE;
    3264                 : 
    3265               0 :   JSObject* proto = JSVAL_TO_OBJECT(*v);
    3266               0 :   while ((proto = JS_GetPrototype(proto))) {
    3267               0 :     if (proto == prototype) {
    3268               0 :       *bp = JS_TRUE;
    3269               0 :       break;
    3270                 :     }
    3271                 :   }
    3272               0 :   return JS_TRUE;
    3273                 : }
    3274                 : 
    3275                 : static JSObject*
    3276               0 : CType::GetGlobalCTypes(JSContext* cx, JSObject* obj)
    3277                 : {
    3278               0 :   JS_ASSERT(CType::IsCType(obj));
    3279                 : 
    3280               0 :   JSObject *objTypeProto = JS_GetPrototype(obj);
    3281                 :   if (!objTypeProto) {
    3282                 :   }
    3283               0 :   JS_ASSERT(objTypeProto);
    3284               0 :   JS_ASSERT(CType::IsCTypeProto(objTypeProto));
    3285                 : 
    3286               0 :   jsval valCTypes = JS_GetReservedSlot(objTypeProto, SLOT_CTYPES);
    3287               0 :   JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCTypes));
    3288                 : 
    3289               0 :   return JSVAL_TO_OBJECT(valCTypes);
    3290                 : }
    3291                 : 
    3292                 : /*******************************************************************************
    3293                 : ** PointerType implementation
    3294                 : *******************************************************************************/
    3295                 : 
    3296                 : JSBool
    3297               0 : PointerType::Create(JSContext* cx, unsigned argc, jsval* vp)
    3298                 : {
    3299                 :   // Construct and return a new PointerType object.
    3300               0 :   if (argc != 1) {
    3301               0 :     JS_ReportError(cx, "PointerType takes one argument");
    3302               0 :     return JS_FALSE;
    3303                 :   }
    3304                 : 
    3305               0 :   jsval arg = JS_ARGV(cx, vp)[0];
    3306               0 :   if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(JSVAL_TO_OBJECT(arg))) {
    3307               0 :     JS_ReportError(cx, "first argument must be a CType");
    3308               0 :     return JS_FALSE;
    3309                 :   }
    3310                 : 
    3311               0 :   JSObject* result = CreateInternal(cx, JSVAL_TO_OBJECT(arg));
    3312               0 :   if (!result)
    3313               0 :     return JS_FALSE;
    3314                 : 
    3315               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3316               0 :   return JS_TRUE;
    3317                 : }
    3318                 : 
    3319                 : JSObject*
    3320           23328 : PointerType::CreateInternal(JSContext* cx, JSObject* baseType)
    3321                 : {
    3322                 :   // check if we have a cached PointerType on our base CType.
    3323           23328 :   jsval slot = JS_GetReservedSlot(baseType, SLOT_PTR);
    3324           23328 :   if (!JSVAL_IS_VOID(slot))
    3325               0 :     return JSVAL_TO_OBJECT(slot);
    3326                 : 
    3327                 :   // Get ctypes.PointerType.prototype and the common prototype for CData objects
    3328                 :   // of this type, or ctypes.FunctionType.prototype for function pointers.
    3329           23328 :   CTypeProtoSlot slotId = CType::GetTypeCode(baseType) == TYPE_function ?
    3330           23328 :     SLOT_FUNCTIONDATAPROTO : SLOT_POINTERDATAPROTO;
    3331           23328 :   JSObject* dataProto = CType::GetProtoFromType(baseType, slotId);
    3332           23328 :   JSObject* typeProto = CType::GetProtoFromType(baseType, SLOT_POINTERPROTO);
    3333                 : 
    3334                 :   // Create a new CType object with the common properties and slots.
    3335                 :   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer,
    3336                 :                         NULL, INT_TO_JSVAL(sizeof(void*)),
    3337           23328 :                         INT_TO_JSVAL(ffi_type_pointer.alignment),
    3338           23328 :                         &ffi_type_pointer);
    3339           23328 :   if (!typeObj)
    3340               0 :     return NULL;
    3341                 : 
    3342                 :   // Set the target type. (This will be 'null' for an opaque pointer type.)
    3343           23328 :   JS_SetReservedSlot(typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType));
    3344                 : 
    3345                 :   // Finally, cache our newly-created PointerType on our pointed-to CType.
    3346           23328 :   JS_SetReservedSlot(baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj));
    3347                 : 
    3348           23328 :   return typeObj;
    3349                 : }
    3350                 : 
    3351                 : JSBool
    3352               0 : PointerType::ConstructData(JSContext* cx,
    3353                 :                            JSObject* obj,
    3354                 :                            unsigned argc,
    3355                 :                            jsval* vp)
    3356                 : {
    3357               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_pointer) {
    3358               0 :     JS_ReportError(cx, "not a PointerType");
    3359               0 :     return JS_FALSE;
    3360                 :   }
    3361                 : 
    3362               0 :   if (argc > 3) {
    3363               0 :     JS_ReportError(cx, "constructor takes 0, 1, 2, or 3 arguments");
    3364               0 :     return JS_FALSE;
    3365                 :   }
    3366                 : 
    3367               0 :   JSObject* result = CData::Create(cx, obj, NULL, NULL, true);
    3368               0 :   if (!result)
    3369               0 :     return JS_FALSE;
    3370                 : 
    3371                 :   // Set return value early, must not observe *vp after
    3372               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3373                 : 
    3374                 :   // There are 3 things that we might be creating here:
    3375                 :   // 1 - A null pointer (no arguments)
    3376                 :   // 2 - An initialized pointer (1 argument)
    3377                 :   // 3 - A closure (1-3 arguments)
    3378                 :   //
    3379                 :   // The API doesn't give us a perfect way to distinguish 2 and 3, but the
    3380                 :   // heuristics we use should be fine.
    3381                 : 
    3382                 :   //
    3383                 :   // Case 1 - Null pointer
    3384                 :   //
    3385               0 :   if (argc == 0)
    3386               0 :     return JS_TRUE;
    3387                 : 
    3388                 :   // Analyze the arguments a bit to decide what to do next.
    3389               0 :   jsval* argv = JS_ARGV(cx, vp);
    3390               0 :   JSObject* baseObj = PointerType::GetBaseType(obj);
    3391               0 :   bool looksLikeClosure = CType::GetTypeCode(baseObj) == TYPE_function &&
    3392               0 :                           JSVAL_IS_OBJECT(argv[0]) &&
    3393               0 :                           JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(argv[0]));
    3394                 : 
    3395                 :   //
    3396                 :   // Case 2 - Initialized pointer
    3397                 :   //
    3398               0 :   if (!looksLikeClosure) {
    3399               0 :     if (argc != 1) {
    3400               0 :       JS_ReportError(cx, "first argument must be a function");
    3401               0 :       return JS_FALSE;
    3402                 :     }
    3403               0 :     return ExplicitConvert(cx, argv[0], obj, CData::GetData(result));
    3404                 :   }
    3405                 : 
    3406                 :   //
    3407                 :   // Case 3 - Closure
    3408                 :   //
    3409                 : 
    3410                 :   // The second argument is an optional 'this' parameter with which to invoke
    3411                 :   // the given js function. Callers may leave this blank, or pass null if they
    3412                 :   // wish to pass the third argument.
    3413               0 :   JSObject* thisObj = NULL;
    3414               0 :   if (argc >= 2) {
    3415               0 :     if (JSVAL_IS_OBJECT(argv[1])) {
    3416               0 :       thisObj = JSVAL_TO_OBJECT(argv[1]);
    3417               0 :     } else if (!JS_ValueToObject(cx, argv[1], &thisObj)) {
    3418               0 :       return JS_FALSE;
    3419                 :     }
    3420                 :   }
    3421                 : 
    3422                 :   // The third argument is an optional error sentinel that js-ctypes will return
    3423                 :   // if an exception is raised while executing the closure. The type must match
    3424                 :   // the return type of the callback.
    3425               0 :   jsval errVal = JSVAL_VOID;
    3426               0 :   if (argc == 3)
    3427               0 :     errVal = argv[2];
    3428                 : 
    3429               0 :   JSObject* fnObj = JSVAL_TO_OBJECT(argv[0]);
    3430               0 :   return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj, errVal);
    3431                 : }
    3432                 : 
    3433                 : JSObject*
    3434               0 : PointerType::GetBaseType(JSObject* obj)
    3435                 : {
    3436               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_pointer);
    3437                 : 
    3438               0 :   jsval type = JS_GetReservedSlot(obj, SLOT_TARGET_T);
    3439               0 :   JS_ASSERT(!JSVAL_IS_NULL(type));
    3440               0 :   return JSVAL_TO_OBJECT(type);
    3441                 : }
    3442                 : 
    3443                 : JSBool
    3444               0 : PointerType::TargetTypeGetter(JSContext* cx,
    3445                 :                               JSObject* obj,
    3446                 :                               jsid idval,
    3447                 :                               jsval* vp)
    3448                 : {
    3449               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_pointer) {
    3450               0 :     JS_ReportError(cx, "not a PointerType");
    3451               0 :     return JS_FALSE;
    3452                 :   }
    3453                 : 
    3454               0 :   *vp = JS_GetReservedSlot(obj, SLOT_TARGET_T);
    3455               0 :   JS_ASSERT(JSVAL_IS_OBJECT(*vp));
    3456               0 :   return JS_TRUE;
    3457                 : }
    3458                 : 
    3459                 : JSBool
    3460               0 : PointerType::IsNull(JSContext* cx, unsigned argc, jsval* vp)
    3461                 : {
    3462               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    3463               0 :   if (!obj || !CData::IsCData(obj)) {
    3464               0 :     JS_ReportError(cx, "not a CData");
    3465               0 :     return JS_FALSE;
    3466                 :   }
    3467                 : 
    3468                 :   // Get pointer type and base type.
    3469               0 :   JSObject* typeObj = CData::GetCType(obj);
    3470               0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    3471               0 :     JS_ReportError(cx, "not a PointerType");
    3472               0 :     return JS_FALSE;
    3473                 :   }
    3474                 : 
    3475               0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    3476               0 :   jsval result = BOOLEAN_TO_JSVAL(data == NULL);
    3477               0 :   JS_SET_RVAL(cx, vp, result);
    3478               0 :   return JS_TRUE;
    3479                 : }
    3480                 : 
    3481                 : JSBool
    3482               0 : PointerType::OffsetBy(JSContext* cx, int offset, jsval* vp)
    3483                 : {
    3484               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    3485               0 :   if (!obj || !CData::IsCData(obj)) {
    3486               0 :     JS_ReportError(cx, "not a CData");
    3487               0 :     return JS_FALSE;
    3488                 :   }
    3489                 : 
    3490               0 :   JSObject* typeObj = CData::GetCType(obj);
    3491               0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    3492               0 :     JS_ReportError(cx, "not a PointerType");
    3493               0 :     return JS_FALSE;
    3494                 :   }
    3495                 : 
    3496               0 :   JSObject* baseType = PointerType::GetBaseType(typeObj);
    3497               0 :   if (!CType::IsSizeDefined(baseType)) {
    3498               0 :     JS_ReportError(cx, "cannot modify pointer of undefined size");
    3499               0 :     return JS_FALSE;
    3500                 :   }
    3501                 : 
    3502               0 :   size_t elementSize = CType::GetSize(baseType);
    3503               0 :   char* data = static_cast<char*>(*static_cast<void**>(CData::GetData(obj)));
    3504               0 :   void* address = data + offset * elementSize;
    3505                 : 
    3506                 :   // Create a PointerType CData object containing the new address.
    3507               0 :   JSObject* result = CData::Create(cx, typeObj, NULL, &address, true);
    3508               0 :   if (!result)
    3509               0 :     return JS_FALSE;
    3510                 : 
    3511               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3512               0 :   return JS_TRUE;
    3513                 : }
    3514                 : 
    3515                 : JSBool
    3516               0 : PointerType::Increment(JSContext* cx, unsigned argc, jsval* vp)
    3517                 : {
    3518               0 :   return OffsetBy(cx, 1, vp);
    3519                 : }
    3520                 : 
    3521                 : JSBool
    3522               0 : PointerType::Decrement(JSContext* cx, unsigned argc, jsval* vp)
    3523                 : {
    3524               0 :   return OffsetBy(cx, -1, vp);
    3525                 : }
    3526                 : 
    3527                 : JSBool
    3528               0 : PointerType::ContentsGetter(JSContext* cx,
    3529                 :                             JSObject* obj,
    3530                 :                             jsid idval,
    3531                 :                             jsval* vp)
    3532                 : {
    3533               0 :   if (!CData::IsCData(obj)) {
    3534               0 :     JS_ReportError(cx, "not a CData");
    3535               0 :     return JS_FALSE;
    3536                 :   }
    3537                 : 
    3538                 :   // Get pointer type and base type.
    3539               0 :   JSObject* typeObj = CData::GetCType(obj);
    3540               0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    3541               0 :     JS_ReportError(cx, "not a PointerType");
    3542               0 :     return JS_FALSE;
    3543                 :   }
    3544                 : 
    3545               0 :   JSObject* baseType = GetBaseType(typeObj);
    3546               0 :   if (!CType::IsSizeDefined(baseType)) {
    3547               0 :     JS_ReportError(cx, "cannot get contents of undefined size");
    3548               0 :     return JS_FALSE;
    3549                 :   }
    3550                 : 
    3551               0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    3552               0 :   if (data == NULL) {
    3553               0 :     JS_ReportError(cx, "cannot read contents of null pointer");
    3554               0 :     return JS_FALSE;
    3555                 :   }
    3556                 : 
    3557                 :   jsval result;
    3558               0 :   if (!ConvertToJS(cx, baseType, NULL, data, false, false, &result))
    3559               0 :     return JS_FALSE;
    3560                 : 
    3561               0 :   JS_SET_RVAL(cx, vp, result);
    3562               0 :   return JS_TRUE;
    3563                 : }
    3564                 : 
    3565                 : JSBool
    3566               0 : PointerType::ContentsSetter(JSContext* cx,
    3567                 :                             JSObject* obj,
    3568                 :                             jsid idval,
    3569                 :                             JSBool strict,
    3570                 :                             jsval* vp)
    3571                 : {
    3572               0 :   if (!CData::IsCData(obj)) {
    3573               0 :     JS_ReportError(cx, "not a CData");
    3574               0 :     return JS_FALSE;
    3575                 :   }
    3576                 : 
    3577                 :   // Get pointer type and base type.
    3578               0 :   JSObject* typeObj = CData::GetCType(obj);
    3579               0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    3580               0 :     JS_ReportError(cx, "not a PointerType");
    3581               0 :     return JS_FALSE;
    3582                 :   }
    3583                 : 
    3584               0 :   JSObject* baseType = GetBaseType(typeObj);
    3585               0 :   if (!CType::IsSizeDefined(baseType)) {
    3586               0 :     JS_ReportError(cx, "cannot set contents of undefined size");
    3587               0 :     return JS_FALSE;
    3588                 :   }
    3589                 : 
    3590               0 :   void* data = *static_cast<void**>(CData::GetData(obj));
    3591               0 :   if (data == NULL) {
    3592               0 :     JS_ReportError(cx, "cannot write contents to null pointer");
    3593               0 :     return JS_FALSE;
    3594                 :   }
    3595                 : 
    3596               0 :   return ImplicitConvert(cx, *vp, baseType, data, false, NULL);
    3597                 : }
    3598                 : 
    3599                 : /*******************************************************************************
    3600                 : ** ArrayType implementation
    3601                 : *******************************************************************************/
    3602                 : 
    3603                 : JSBool
    3604               0 : ArrayType::Create(JSContext* cx, unsigned argc, jsval* vp)
    3605                 : {
    3606                 :   // Construct and return a new ArrayType object.
    3607               0 :   if (argc < 1 || argc > 2) {
    3608               0 :     JS_ReportError(cx, "ArrayType takes one or two arguments");
    3609               0 :     return JS_FALSE;
    3610                 :   }
    3611                 : 
    3612               0 :   jsval* argv = JS_ARGV(cx, vp);
    3613               0 :   if (JSVAL_IS_PRIMITIVE(argv[0]) ||
    3614               0 :       !CType::IsCType(JSVAL_TO_OBJECT(argv[0]))) {
    3615               0 :     JS_ReportError(cx, "first argument must be a CType");
    3616               0 :     return JS_FALSE;
    3617                 :   }
    3618                 : 
    3619                 :   // Convert the length argument to a size_t.
    3620               0 :   size_t length = 0;
    3621               0 :   if (argc == 2 && !jsvalToSize(cx, argv[1], false, &length)) {
    3622               0 :     JS_ReportError(cx, "second argument must be a nonnegative integer");
    3623               0 :     return JS_FALSE;
    3624                 :   }
    3625                 : 
    3626               0 :   JSObject* baseType = JSVAL_TO_OBJECT(argv[0]);
    3627               0 :   JSObject* result = CreateInternal(cx, baseType, length, argc == 2);
    3628               0 :   if (!result)
    3629               0 :     return JS_FALSE;
    3630                 : 
    3631               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3632               0 :   return JS_TRUE;
    3633                 : }
    3634                 : 
    3635                 : JSObject*
    3636               0 : ArrayType::CreateInternal(JSContext* cx,
    3637                 :                           JSObject* baseType,
    3638                 :                           size_t length,
    3639                 :                           bool lengthDefined)
    3640                 : {
    3641                 :   // Get ctypes.ArrayType.prototype and the common prototype for CData objects
    3642                 :   // of this type, from ctypes.CType.prototype.
    3643               0 :   JSObject* typeProto = CType::GetProtoFromType(baseType, SLOT_ARRAYPROTO);
    3644               0 :   JSObject* dataProto = CType::GetProtoFromType(baseType, SLOT_ARRAYDATAPROTO);
    3645                 : 
    3646                 :   // Determine the size of the array from the base type, if possible.
    3647                 :   // The size of the base type must be defined.
    3648                 :   // If our length is undefined, both our size and length will be undefined.
    3649                 :   size_t baseSize;
    3650               0 :   if (!CType::GetSafeSize(baseType, &baseSize)) {
    3651               0 :     JS_ReportError(cx, "base size must be defined");
    3652               0 :     return NULL;
    3653                 :   }
    3654                 : 
    3655               0 :   jsval sizeVal = JSVAL_VOID;
    3656               0 :   jsval lengthVal = JSVAL_VOID;
    3657               0 :   if (lengthDefined) {
    3658                 :     // Check for overflow, and convert to an int or double as required.
    3659               0 :     size_t size = length * baseSize;
    3660               0 :     if (length > 0 && size / length != baseSize) {
    3661               0 :       JS_ReportError(cx, "size overflow");
    3662               0 :       return NULL;
    3663                 :     }
    3664               0 :     if (!SizeTojsval(cx, size, &sizeVal) ||
    3665               0 :         !SizeTojsval(cx, length, &lengthVal))
    3666               0 :       return NULL;
    3667                 :   }
    3668                 : 
    3669               0 :   size_t align = CType::GetAlignment(baseType);
    3670                 : 
    3671                 :   // Create a new CType object with the common properties and slots.
    3672                 :   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_array, NULL,
    3673               0 :                         sizeVal, INT_TO_JSVAL(align), NULL);
    3674               0 :   if (!typeObj)
    3675               0 :     return NULL;
    3676                 : 
    3677                 :   // Set the element type.
    3678               0 :   JS_SetReservedSlot(typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType));
    3679                 : 
    3680                 :   // Set the length.
    3681               0 :   JS_SetReservedSlot(typeObj, SLOT_LENGTH, lengthVal);
    3682                 : 
    3683               0 :   return typeObj;
    3684                 : }
    3685                 : 
    3686                 : JSBool
    3687               0 : ArrayType::ConstructData(JSContext* cx,
    3688                 :                          JSObject* obj,
    3689                 :                          unsigned argc,
    3690                 :                          jsval* vp)
    3691                 : {
    3692               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
    3693               0 :     JS_ReportError(cx, "not an ArrayType");
    3694               0 :     return JS_FALSE;
    3695                 :   }
    3696                 : 
    3697                 :   // Decide whether we have an object to initialize from. We'll override this
    3698                 :   // if we get a length argument instead.
    3699               0 :   bool convertObject = argc == 1;
    3700                 : 
    3701                 :   // Check if we're an array of undefined length. If we are, allow construction
    3702                 :   // with a length argument, or with an actual JS array.
    3703               0 :   if (CType::IsSizeDefined(obj)) {
    3704               0 :     if (argc > 1) {
    3705               0 :       JS_ReportError(cx, "constructor takes zero or one argument");
    3706               0 :       return JS_FALSE;
    3707                 :     }
    3708                 : 
    3709                 :   } else {
    3710               0 :     if (argc != 1) {
    3711               0 :       JS_ReportError(cx, "constructor takes one argument");
    3712               0 :       return JS_FALSE;
    3713                 :     }
    3714                 : 
    3715               0 :     JSObject* baseType = GetBaseType(obj);
    3716                 : 
    3717               0 :     jsval* argv = JS_ARGV(cx, vp);
    3718                 :     size_t length;
    3719               0 :     if (jsvalToSize(cx, argv[0], false, &length)) {
    3720                 :       // Have a length, rather than an object to initialize from.
    3721               0 :       convertObject = false;
    3722                 : 
    3723               0 :     } else if (!JSVAL_IS_PRIMITIVE(argv[0])) {
    3724                 :       // We were given an object with a .length property.
    3725                 :       // This could be a JS array, or a CData array.
    3726               0 :       JSObject* arg = JSVAL_TO_OBJECT(argv[0]);
    3727               0 :       js::AutoValueRooter lengthVal(cx);
    3728               0 :       if (!JS_GetProperty(cx, arg, "length", lengthVal.jsval_addr()) ||
    3729               0 :           !jsvalToSize(cx, lengthVal.jsval_value(), false, &length)) {
    3730               0 :         JS_ReportError(cx, "argument must be an array object or length");
    3731               0 :         return JS_FALSE;
    3732                 :       }
    3733                 : 
    3734               0 :     } else if (JSVAL_IS_STRING(argv[0])) {
    3735                 :       // We were given a string. Size the array to the appropriate length,
    3736                 :       // including space for the terminator.
    3737               0 :       JSString* sourceString = JSVAL_TO_STRING(argv[0]);
    3738               0 :       size_t sourceLength = sourceString->length();
    3739               0 :       const jschar* sourceChars = sourceString->getChars(cx);
    3740               0 :       if (!sourceChars)
    3741               0 :         return false;
    3742                 : 
    3743               0 :       switch (CType::GetTypeCode(baseType)) {
    3744                 :       case TYPE_char:
    3745                 :       case TYPE_signed_char:
    3746                 :       case TYPE_unsigned_char: {
    3747                 :         // Determine the UTF-8 length.
    3748               0 :         length = GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
    3749               0 :         if (length == (size_t) -1)
    3750               0 :           return false;
    3751                 : 
    3752               0 :         ++length;
    3753               0 :         break;
    3754                 :       }
    3755                 :       case TYPE_jschar:
    3756               0 :         length = sourceLength + 1;
    3757               0 :         break;
    3758                 :       default:
    3759               0 :         return TypeError(cx, "array", argv[0]);
    3760                 :       }
    3761                 : 
    3762                 :     } else {
    3763               0 :       JS_ReportError(cx, "argument must be an array object or length");
    3764               0 :       return JS_FALSE;
    3765                 :     }
    3766                 : 
    3767                 :     // Construct a new ArrayType of defined length, for the new CData object.
    3768               0 :     obj = CreateInternal(cx, baseType, length, true);
    3769               0 :     if (!obj)
    3770               0 :       return JS_FALSE;
    3771                 :   }
    3772                 : 
    3773                 :   // Root the CType object, in case we created one above.
    3774               0 :   js::AutoObjectRooter root(cx, obj);
    3775                 : 
    3776               0 :   JSObject* result = CData::Create(cx, obj, NULL, NULL, true);
    3777               0 :   if (!result)
    3778               0 :     return JS_FALSE;
    3779                 : 
    3780               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    3781                 : 
    3782               0 :   if (convertObject) {
    3783               0 :     if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(result)))
    3784               0 :       return JS_FALSE;
    3785                 :   }
    3786                 : 
    3787               0 :   return JS_TRUE;
    3788                 : }
    3789                 : 
    3790                 : JSObject*
    3791               0 : ArrayType::GetBaseType(JSObject* obj)
    3792                 : {
    3793               0 :   JS_ASSERT(CType::IsCType(obj));
    3794               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    3795                 : 
    3796               0 :   jsval type = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
    3797               0 :   JS_ASSERT(!JSVAL_IS_NULL(type));
    3798               0 :   return JSVAL_TO_OBJECT(type);
    3799                 : }
    3800                 : 
    3801                 : bool
    3802               0 : ArrayType::GetSafeLength(JSObject* obj, size_t* result)
    3803                 : {
    3804               0 :   JS_ASSERT(CType::IsCType(obj));
    3805               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    3806                 : 
    3807               0 :   jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
    3808                 : 
    3809                 :   // The "length" property can be an int, a double, or JSVAL_VOID
    3810                 :   // (for arrays of undefined length), and must always fit in a size_t.
    3811               0 :   if (JSVAL_IS_INT(length)) {
    3812               0 :     *result = JSVAL_TO_INT(length);
    3813               0 :     return true;
    3814                 :   }
    3815               0 :   if (JSVAL_IS_DOUBLE(length)) {
    3816               0 :     *result = Convert<size_t>(JSVAL_TO_DOUBLE(length));
    3817               0 :     return true;
    3818                 :   }
    3819                 : 
    3820               0 :   JS_ASSERT(JSVAL_IS_VOID(length));
    3821               0 :   return false;
    3822                 : }
    3823                 : 
    3824                 : size_t
    3825               0 : ArrayType::GetLength(JSObject* obj)
    3826                 : {
    3827               0 :   JS_ASSERT(CType::IsCType(obj));
    3828               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    3829                 : 
    3830               0 :   jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
    3831                 : 
    3832               0 :   JS_ASSERT(!JSVAL_IS_VOID(length));
    3833                 : 
    3834                 :   // The "length" property can be an int, a double, or JSVAL_VOID
    3835                 :   // (for arrays of undefined length), and must always fit in a size_t.
    3836                 :   // For callers who know it can never be JSVAL_VOID, return a size_t directly.
    3837               0 :   if (JSVAL_IS_INT(length))
    3838               0 :     return JSVAL_TO_INT(length);
    3839               0 :   return Convert<size_t>(JSVAL_TO_DOUBLE(length));
    3840                 : }
    3841                 : 
    3842                 : ffi_type*
    3843               0 : ArrayType::BuildFFIType(JSContext* cx, JSObject* obj)
    3844                 : {
    3845               0 :   JS_ASSERT(CType::IsCType(obj));
    3846               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_array);
    3847               0 :   JS_ASSERT(CType::IsSizeDefined(obj));
    3848                 : 
    3849               0 :   JSObject* baseType = ArrayType::GetBaseType(obj);
    3850               0 :   ffi_type* ffiBaseType = CType::GetFFIType(cx, baseType);
    3851               0 :   if (!ffiBaseType)
    3852               0 :     return NULL;
    3853                 : 
    3854               0 :   size_t length = ArrayType::GetLength(obj);
    3855                 : 
    3856                 :   // Create an ffi_type to represent the array. This is necessary for the case
    3857                 :   // where the array is part of a struct. Since libffi has no intrinsic
    3858                 :   // support for array types, we approximate it by creating a struct type
    3859                 :   // with elements of type 'baseType' and with appropriate size and alignment
    3860                 :   // values. It would be nice to not do all the work of setting up 'elements',
    3861                 :   // but some libffi platforms currently require that it be meaningful. I'm
    3862                 :   // looking at you, x86_64.
    3863               0 :   AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
    3864               0 :   if (!ffiType) {
    3865               0 :     JS_ReportOutOfMemory(cx);
    3866               0 :     return NULL;
    3867                 :   }
    3868                 : 
    3869               0 :   ffiType->type = FFI_TYPE_STRUCT;
    3870               0 :   ffiType->size = CType::GetSize(obj);
    3871               0 :   ffiType->alignment = CType::GetAlignment(obj);
    3872               0 :   ffiType->elements = cx->array_new<ffi_type*>(length + 1);
    3873               0 :   if (!ffiType->elements) {
    3874               0 :     JS_ReportAllocationOverflow(cx);
    3875               0 :     return NULL;
    3876                 :   }
    3877                 : 
    3878               0 :   for (size_t i = 0; i < length; ++i)
    3879               0 :     ffiType->elements[i] = ffiBaseType;
    3880               0 :   ffiType->elements[length] = NULL;
    3881                 : 
    3882               0 :   return ffiType.forget();
    3883                 : }
    3884                 : 
    3885                 : JSBool
    3886               0 : ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3887                 : {
    3888               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
    3889               0 :     JS_ReportError(cx, "not an ArrayType");
    3890               0 :     return JS_FALSE;
    3891                 :   }
    3892                 : 
    3893               0 :   *vp = JS_GetReservedSlot(obj, SLOT_ELEMENT_T);
    3894               0 :   JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
    3895               0 :   return JS_TRUE;
    3896                 : }
    3897                 : 
    3898                 : JSBool
    3899               0 : ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3900                 : {
    3901                 :   // This getter exists for both CTypes and CDatas of the ArrayType persuasion.
    3902                 :   // If we're dealing with a CData, get the CType from it.
    3903               0 :   if (CData::IsCData(obj))
    3904               0 :     obj = CData::GetCType(obj);
    3905                 : 
    3906               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_array) {
    3907               0 :     JS_ReportError(cx, "not an ArrayType");
    3908               0 :     return JS_FALSE;
    3909                 :   }
    3910                 : 
    3911               0 :   *vp = JS_GetReservedSlot(obj, SLOT_LENGTH);
    3912               0 :   JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp));
    3913               0 :   return JS_TRUE;
    3914                 : }
    3915                 : 
    3916                 : JSBool
    3917               0 : ArrayType::Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    3918                 : {
    3919                 :   // This should never happen, but we'll check to be safe.
    3920               0 :   if (!CData::IsCData(obj)) {
    3921               0 :     JS_ReportError(cx, "not a CData");
    3922               0 :     return JS_FALSE;
    3923                 :   }
    3924                 : 
    3925                 :   // Bail early if we're not an ArrayType. (This setter is present for all
    3926                 :   // CData, regardless of CType.)
    3927               0 :   JSObject* typeObj = CData::GetCType(obj);
    3928               0 :   if (CType::GetTypeCode(typeObj) != TYPE_array)
    3929               0 :     return JS_TRUE;
    3930                 : 
    3931                 :   // Convert the index to a size_t and bounds-check it.
    3932                 :   size_t index;
    3933               0 :   size_t length = GetLength(typeObj);
    3934               0 :   bool ok = jsidToSize(cx, idval, true, &index);
    3935               0 :   if (!ok && JSID_IS_STRING(idval)) {
    3936                 :     // String either isn't a number, or doesn't fit in size_t.
    3937                 :     // Chances are it's a regular property lookup, so return.
    3938               0 :     return JS_TRUE;
    3939                 :   }
    3940               0 :   if (!ok || index >= length) {
    3941               0 :     JS_ReportError(cx, "invalid index");
    3942               0 :     return JS_FALSE;
    3943                 :   }
    3944                 : 
    3945               0 :   JSObject* baseType = GetBaseType(typeObj);
    3946               0 :   size_t elementSize = CType::GetSize(baseType);
    3947               0 :   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    3948               0 :   return ConvertToJS(cx, baseType, obj, data, false, false, vp);
    3949                 : }
    3950                 : 
    3951                 : JSBool
    3952               0 : ArrayType::Setter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp)
    3953                 : {
    3954                 :   // This should never happen, but we'll check to be safe.
    3955               0 :   if (!CData::IsCData(obj)) {
    3956               0 :     JS_ReportError(cx, "not a CData");
    3957               0 :     return JS_FALSE;
    3958                 :   }
    3959                 : 
    3960                 :   // Bail early if we're not an ArrayType. (This setter is present for all
    3961                 :   // CData, regardless of CType.)
    3962               0 :   JSObject* typeObj = CData::GetCType(obj);
    3963               0 :   if (CType::GetTypeCode(typeObj) != TYPE_array)
    3964               0 :     return JS_TRUE;
    3965                 : 
    3966                 :   // Convert the index to a size_t and bounds-check it.
    3967                 :   size_t index;
    3968               0 :   size_t length = GetLength(typeObj);
    3969               0 :   bool ok = jsidToSize(cx, idval, true, &index);
    3970               0 :   if (!ok && JSID_IS_STRING(idval)) {
    3971                 :     // String either isn't a number, or doesn't fit in size_t.
    3972                 :     // Chances are it's a regular property lookup, so return.
    3973               0 :     return JS_TRUE;
    3974                 :   }
    3975               0 :   if (!ok || index >= length) {
    3976               0 :     JS_ReportError(cx, "invalid index");
    3977               0 :     return JS_FALSE;
    3978                 :   }
    3979                 : 
    3980               0 :   JSObject* baseType = GetBaseType(typeObj);
    3981               0 :   size_t elementSize = CType::GetSize(baseType);
    3982               0 :   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    3983               0 :   return ImplicitConvert(cx, *vp, baseType, data, false, NULL);
    3984                 : }
    3985                 : 
    3986                 : JSBool
    3987               0 : ArrayType::AddressOfElement(JSContext* cx, unsigned argc, jsval* vp)
    3988                 : {
    3989               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    3990               0 :   if (!obj || !CData::IsCData(obj)) {
    3991               0 :     JS_ReportError(cx, "not a CData");
    3992               0 :     return JS_FALSE;
    3993                 :   }
    3994                 : 
    3995               0 :   JSObject* typeObj = CData::GetCType(obj);
    3996               0 :   if (CType::GetTypeCode(typeObj) != TYPE_array) {
    3997               0 :     JS_ReportError(cx, "not an ArrayType");
    3998               0 :     return JS_FALSE;
    3999                 :   }
    4000                 : 
    4001               0 :   if (argc != 1) {
    4002               0 :     JS_ReportError(cx, "addressOfElement takes one argument");
    4003               0 :     return JS_FALSE;
    4004                 :   }
    4005                 : 
    4006               0 :   JSObject* baseType = GetBaseType(typeObj);
    4007               0 :   JSObject* pointerType = PointerType::CreateInternal(cx, baseType);
    4008               0 :   if (!pointerType)
    4009               0 :     return JS_FALSE;
    4010               0 :   js::AutoObjectRooter root(cx, pointerType);
    4011                 : 
    4012                 :   // Create a PointerType CData object containing null.
    4013               0 :   JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true);
    4014               0 :   if (!result)
    4015               0 :     return JS_FALSE;
    4016                 : 
    4017               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    4018                 : 
    4019                 :   // Convert the index to a size_t and bounds-check it.
    4020                 :   size_t index;
    4021               0 :   size_t length = GetLength(typeObj);
    4022               0 :   if (!jsvalToSize(cx, JS_ARGV(cx, vp)[0], false, &index) ||
    4023                 :       index >= length) {
    4024               0 :     JS_ReportError(cx, "invalid index");
    4025               0 :     return JS_FALSE;
    4026                 :   }
    4027                 : 
    4028                 :   // Manually set the pointer inside the object, so we skip the conversion step.
    4029               0 :   void** data = static_cast<void**>(CData::GetData(result));
    4030               0 :   size_t elementSize = CType::GetSize(baseType);
    4031               0 :   *data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
    4032               0 :   return JS_TRUE;
    4033                 : }
    4034                 : 
    4035                 : /*******************************************************************************
    4036                 : ** StructType implementation
    4037                 : *******************************************************************************/
    4038                 : 
    4039                 : // For a struct field descriptor 'val' of the form { name : type }, extract
    4040                 : // 'name' and 'type'.
    4041                 : static JSFlatString*
    4042               0 : ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
    4043                 : {
    4044               0 :   if (JSVAL_IS_PRIMITIVE(val)) {
    4045               0 :     JS_ReportError(cx, "struct field descriptors require a valid name and type");
    4046               0 :     return NULL;
    4047                 :   }
    4048                 : 
    4049               0 :   JSObject* obj = JSVAL_TO_OBJECT(val);
    4050               0 :   JSObject* iter = JS_NewPropertyIterator(cx, obj);
    4051               0 :   if (!iter)
    4052               0 :     return NULL;
    4053               0 :   js::AutoObjectRooter iterroot(cx, iter);
    4054                 : 
    4055                 :   jsid nameid;
    4056               0 :   if (!JS_NextProperty(cx, iter, &nameid))
    4057               0 :     return NULL;
    4058               0 :   if (JSID_IS_VOID(nameid)) {
    4059               0 :     JS_ReportError(cx, "struct field descriptors require a valid name and type");
    4060               0 :     return NULL;
    4061                 :   }
    4062                 : 
    4063               0 :   if (!JSID_IS_STRING(nameid)) {
    4064               0 :     JS_ReportError(cx, "struct field descriptors require a valid name and type");
    4065               0 :     return NULL;
    4066                 :   }
    4067                 : 
    4068                 :   // make sure we have one, and only one, property
    4069                 :   jsid id;
    4070               0 :   if (!JS_NextProperty(cx, iter, &id))
    4071               0 :     return NULL;
    4072               0 :   if (!JSID_IS_VOID(id)) {
    4073               0 :     JS_ReportError(cx, "struct field descriptors must contain one property");
    4074               0 :     return NULL;
    4075                 :   }
    4076                 : 
    4077               0 :   js::AutoValueRooter propVal(cx);
    4078               0 :   if (!JS_GetPropertyById(cx, obj, nameid, propVal.jsval_addr()))
    4079               0 :     return NULL;
    4080                 : 
    4081               0 :   if (propVal.value().isPrimitive() ||
    4082               0 :       !CType::IsCType(JSVAL_TO_OBJECT(propVal.jsval_value()))) {
    4083               0 :     JS_ReportError(cx, "struct field descriptors require a valid name and type");
    4084               0 :     return NULL;
    4085                 :   }
    4086                 : 
    4087                 :   // Undefined size or zero size struct members are illegal.
    4088                 :   // (Zero-size arrays are legal as struct members in C++, but libffi will
    4089                 :   // choke on a zero-size struct, so we disallow them.)
    4090               0 :   *typeObj = JSVAL_TO_OBJECT(propVal.jsval_value());
    4091                 :   size_t size;
    4092               0 :   if (!CType::GetSafeSize(*typeObj, &size) || size == 0) {
    4093               0 :     JS_ReportError(cx, "struct field types must have defined and nonzero size");
    4094               0 :     return NULL;
    4095                 :   }
    4096                 : 
    4097               0 :   return JSID_TO_FLAT_STRING(nameid);
    4098                 : }
    4099                 : 
    4100                 : // For a struct field with 'name' and 'type', add an element of the form
    4101                 : // { name : type }.
    4102                 : static JSBool
    4103               0 : AddFieldToArray(JSContext* cx,
    4104                 :                 jsval* element,
    4105                 :                 JSFlatString* name,
    4106                 :                 JSObject* typeObj)
    4107                 : {
    4108               0 :   JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL);
    4109               0 :   if (!fieldObj)
    4110               0 :     return false;
    4111                 : 
    4112               0 :   *element = OBJECT_TO_JSVAL(fieldObj);
    4113                 : 
    4114               0 :   if (!JS_DefineUCProperty(cx, fieldObj,
    4115                 :          name->chars(), name->length(),
    4116                 :          OBJECT_TO_JSVAL(typeObj), NULL, NULL,
    4117               0 :          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
    4118               0 :     return false;
    4119                 : 
    4120               0 :   return JS_FreezeObject(cx, fieldObj);
    4121                 : }
    4122                 : 
    4123                 : JSBool
    4124               0 : StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
    4125                 : {
    4126                 :   // Construct and return a new StructType object.
    4127               0 :   if (argc < 1 || argc > 2) {
    4128               0 :     JS_ReportError(cx, "StructType takes one or two arguments");
    4129               0 :     return JS_FALSE;
    4130                 :   }
    4131                 : 
    4132               0 :   jsval* argv = JS_ARGV(cx, vp);
    4133               0 :   jsval name = argv[0];
    4134               0 :   if (!JSVAL_IS_STRING(name)) {
    4135               0 :     JS_ReportError(cx, "first argument must be a string");
    4136               0 :     return JS_FALSE;
    4137                 :   }
    4138                 : 
    4139                 :   // Get ctypes.StructType.prototype from the ctypes.StructType constructor.
    4140               0 :   JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
    4141               0 :   JSObject* typeProto = CType::GetProtoFromCtor(callee, SLOT_STRUCTPROTO);
    4142                 : 
    4143                 :   // Create a simple StructType with no defined fields. The result will be
    4144                 :   // non-instantiable as CData, will have no 'prototype' property, and will
    4145                 :   // have undefined size and alignment and no ffi_type.
    4146                 :   JSObject* result = CType::Create(cx, typeProto, NULL, TYPE_struct,
    4147               0 :                        JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, NULL);
    4148               0 :   if (!result)
    4149               0 :     return JS_FALSE;
    4150               0 :   js::AutoObjectRooter root(cx, result);
    4151                 : 
    4152               0 :   if (argc == 2) {
    4153               0 :     if (JSVAL_IS_PRIMITIVE(argv[1]) ||
    4154               0 :         !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[1]))) {
    4155               0 :       JS_ReportError(cx, "second argument must be an array");
    4156               0 :       return JS_FALSE;
    4157                 :     }
    4158                 : 
    4159                 :     // Define the struct fields.
    4160               0 :     if (!DefineInternal(cx, result, JSVAL_TO_OBJECT(argv[1])))
    4161               0 :       return JS_FALSE;
    4162                 :   }
    4163                 : 
    4164               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    4165               0 :   return JS_TRUE;
    4166                 : }
    4167                 : 
    4168                 : JSBool
    4169               0 : StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj)
    4170                 : {
    4171                 :   uint32_t len;
    4172               0 :   ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len));
    4173                 : 
    4174                 :   // Get the common prototype for CData objects of this type from
    4175                 :   // ctypes.CType.prototype.
    4176               0 :   JSObject* dataProto = CType::GetProtoFromType(typeObj, SLOT_STRUCTDATAPROTO);
    4177                 : 
    4178                 :   // Set up the 'prototype' and 'prototype.constructor' properties.
    4179                 :   // The prototype will reflect the struct fields as properties on CData objects
    4180                 :   // created from this type.
    4181               0 :   JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, NULL);
    4182               0 :   if (!prototype)
    4183               0 :     return JS_FALSE;
    4184               0 :   js::AutoObjectRooter protoroot(cx, prototype);
    4185                 : 
    4186               0 :   if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj),
    4187               0 :          NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT))
    4188               0 :     return JS_FALSE;
    4189                 : 
    4190                 :   // Create a FieldInfoHash to stash on the type object, and an array to root
    4191                 :   // its constituents. (We cannot simply stash the hash in a reserved slot now
    4192                 :   // to get GC safety for free, since if anything in this function fails we
    4193                 :   // do not want to mutate 'typeObj'.)
    4194               0 :   AutoPtr<FieldInfoHash> fields(cx->new_<FieldInfoHash>());
    4195               0 :   Array<jsval, 16> fieldRootsArray;
    4196               0 :   if (!fields || !fields->init(len) || !fieldRootsArray.appendN(JSVAL_VOID, len)) {
    4197               0 :     JS_ReportOutOfMemory(cx);
    4198               0 :     return JS_FALSE;
    4199                 :   }
    4200                 :   js::AutoArrayRooter fieldRoots(cx, fieldRootsArray.length(), 
    4201               0 :     fieldRootsArray.begin());
    4202                 : 
    4203                 :   // Process the field types.
    4204                 :   size_t structSize, structAlign;
    4205               0 :   if (len != 0) {
    4206               0 :     structSize = 0;
    4207               0 :     structAlign = 0;
    4208                 : 
    4209               0 :     for (uint32_t i = 0; i < len; ++i) {
    4210               0 :       js::AutoValueRooter item(cx);
    4211               0 :       if (!JS_GetElement(cx, fieldsObj, i, item.jsval_addr()))
    4212               0 :         return JS_FALSE;
    4213                 : 
    4214               0 :       JSObject* fieldType = NULL;
    4215               0 :       JSFlatString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
    4216               0 :       if (!name)
    4217               0 :         return JS_FALSE;
    4218               0 :       fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType);
    4219                 : 
    4220                 :       // Make sure each field name is unique, and add it to the hash.
    4221               0 :       FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
    4222               0 :       if (entryPtr) {
    4223               0 :         JS_ReportError(cx, "struct fields must have unique names");
    4224               0 :         return JS_FALSE;
    4225                 :       }
    4226               0 :       ASSERT_OK(fields->add(entryPtr, name, FieldInfo()));
    4227               0 :       FieldInfo& info = entryPtr->value;
    4228               0 :       info.mType = fieldType;
    4229               0 :       info.mIndex = i;
    4230                 : 
    4231                 :       // Add the field to the StructType's 'prototype' property.
    4232               0 :       if (!JS_DefineUCProperty(cx, prototype,
    4233                 :              name->chars(), name->length(), JSVAL_VOID,
    4234                 :              StructType::FieldGetter, StructType::FieldSetter,
    4235               0 :              JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT))
    4236               0 :         return JS_FALSE;
    4237                 : 
    4238               0 :       size_t fieldSize = CType::GetSize(fieldType);
    4239               0 :       size_t fieldAlign = CType::GetAlignment(fieldType);
    4240               0 :       size_t fieldOffset = Align(structSize, fieldAlign);
    4241                 :       // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
    4242                 :       // be zero, we can safely check fieldOffset + fieldSize without first
    4243                 :       // checking fieldOffset for overflow.
    4244               0 :       if (fieldOffset + fieldSize < structSize) {
    4245               0 :         JS_ReportError(cx, "size overflow");
    4246               0 :         return JS_FALSE;
    4247                 :       }
    4248               0 :       info.mOffset = fieldOffset;
    4249               0 :       structSize = fieldOffset + fieldSize;
    4250                 : 
    4251               0 :       if (fieldAlign > structAlign)
    4252               0 :         structAlign = fieldAlign;
    4253                 :     }
    4254                 : 
    4255                 :     // Pad the struct tail according to struct alignment.
    4256               0 :     size_t structTail = Align(structSize, structAlign);
    4257               0 :     if (structTail < structSize) {
    4258               0 :       JS_ReportError(cx, "size overflow");
    4259               0 :       return JS_FALSE;
    4260                 :     }
    4261               0 :     structSize = structTail;
    4262                 : 
    4263                 :   } else {
    4264                 :     // Empty structs are illegal in C, but are legal and have a size of
    4265                 :     // 1 byte in C++. We're going to allow them, and trick libffi into
    4266                 :     // believing this by adding a char member. The resulting struct will have
    4267                 :     // no getters or setters, and will be initialized to zero.
    4268               0 :     structSize = 1;
    4269               0 :     structAlign = 1;
    4270                 :   }
    4271                 : 
    4272                 :   jsval sizeVal;
    4273               0 :   if (!SizeTojsval(cx, structSize, &sizeVal))
    4274               0 :     return JS_FALSE;
    4275                 : 
    4276               0 :   JS_SetReservedSlot(typeObj, SLOT_FIELDINFO, PRIVATE_TO_JSVAL(fields.forget()));
    4277                 : 
    4278               0 :   JS_SetReservedSlot(typeObj, SLOT_SIZE, sizeVal);
    4279               0 :   JS_SetReservedSlot(typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign));
    4280                 :   //if (!JS_FreezeObject(cx, prototype)0 // XXX fixme - see bug 541212!
    4281                 :   //  return false;
    4282               0 :   JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
    4283               0 :   return JS_TRUE;
    4284                 : }
    4285                 : 
    4286                 : ffi_type*
    4287               0 : StructType::BuildFFIType(JSContext* cx, JSObject* obj)
    4288                 : {
    4289               0 :   JS_ASSERT(CType::IsCType(obj));
    4290               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    4291               0 :   JS_ASSERT(CType::IsSizeDefined(obj));
    4292                 : 
    4293               0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    4294               0 :   size_t len = fields->count();
    4295                 : 
    4296               0 :   size_t structSize = CType::GetSize(obj);
    4297               0 :   size_t structAlign = CType::GetAlignment(obj);
    4298                 : 
    4299               0 :   AutoPtr<ffi_type> ffiType(cx->new_<ffi_type>());
    4300               0 :   if (!ffiType) {
    4301               0 :     JS_ReportOutOfMemory(cx);
    4302               0 :     return NULL;
    4303                 :   }
    4304               0 :   ffiType->type = FFI_TYPE_STRUCT;
    4305                 : 
    4306               0 :   AutoPtr<ffi_type*>::Array elements;
    4307               0 :   if (len != 0) {
    4308               0 :     elements = cx->array_new<ffi_type*>(len + 1);
    4309               0 :     if (!elements) {
    4310               0 :       JS_ReportOutOfMemory(cx);
    4311               0 :       return NULL;
    4312                 :     }
    4313               0 :     elements[len] = NULL;
    4314                 : 
    4315               0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    4316               0 :       const FieldInfoHash::Entry& entry = r.front();
    4317               0 :       ffi_type* fieldType = CType::GetFFIType(cx, entry.value.mType);
    4318               0 :       if (!fieldType)
    4319               0 :         return NULL;
    4320               0 :       elements[entry.value.mIndex] = fieldType;
    4321                 :     }
    4322                 : 
    4323                 :   } else {
    4324                 :     // Represent an empty struct as having a size of 1 byte, just like C++.
    4325               0 :     JS_ASSERT(structSize == 1);
    4326               0 :     JS_ASSERT(structAlign == 1);
    4327               0 :     elements = cx->array_new<ffi_type*>(2);
    4328               0 :     if (!elements) {
    4329               0 :       JS_ReportOutOfMemory(cx);
    4330               0 :       return NULL;
    4331                 :     }
    4332               0 :     elements[0] = &ffi_type_uint8;
    4333               0 :     elements[1] = NULL;
    4334                 :   }
    4335                 : 
    4336               0 :   ffiType->elements = elements.get();
    4337                 : 
    4338                 : #ifdef DEBUG
    4339                 :   // Perform a sanity check: the result of our struct size and alignment
    4340                 :   // calculations should match libffi's. We force it to do this calculation
    4341                 :   // by calling ffi_prep_cif.
    4342                 :   ffi_cif cif;
    4343               0 :   ffiType->size = 0;
    4344               0 :   ffiType->alignment = 0;
    4345               0 :   ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), NULL);
    4346               0 :   JS_ASSERT(status == FFI_OK);
    4347               0 :   JS_ASSERT(structSize == ffiType->size);
    4348               0 :   JS_ASSERT(structAlign == ffiType->alignment);
    4349                 : #else
    4350                 :   // Fill in the ffi_type's size and align fields. This makes libffi treat the
    4351                 :   // type as initialized; it will not recompute the values. (We assume
    4352                 :   // everything agrees; if it doesn't, we really want to know about it, which
    4353                 :   // is the purpose of the above debug-only check.)
    4354                 :   ffiType->size = structSize;
    4355                 :   ffiType->alignment = structAlign;
    4356                 : #endif
    4357                 : 
    4358               0 :   elements.forget();
    4359               0 :   return ffiType.forget();
    4360                 : }
    4361                 : 
    4362                 : JSBool
    4363               0 : StructType::Define(JSContext* cx, unsigned argc, jsval* vp)
    4364                 : {
    4365               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    4366               0 :   if (!obj ||
    4367               0 :       !CType::IsCType(obj) ||
    4368               0 :       CType::GetTypeCode(obj) != TYPE_struct) {
    4369               0 :     JS_ReportError(cx, "not a StructType");
    4370               0 :     return JS_FALSE;
    4371                 :   }
    4372                 : 
    4373               0 :   if (CType::IsSizeDefined(obj)) {
    4374               0 :     JS_ReportError(cx, "StructType has already been defined");
    4375               0 :     return JS_FALSE;
    4376                 :   }
    4377                 : 
    4378               0 :   if (argc != 1) {
    4379               0 :     JS_ReportError(cx, "define takes one argument");
    4380               0 :     return JS_FALSE;
    4381                 :   }
    4382                 : 
    4383               0 :   jsval arg = JS_ARGV(cx, vp)[0];
    4384               0 :   if (JSVAL_IS_PRIMITIVE(arg) ||
    4385               0 :       !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(arg))) {
    4386               0 :     JS_ReportError(cx, "argument must be an array");
    4387               0 :     return JS_FALSE;
    4388                 :   }
    4389                 : 
    4390               0 :   return DefineInternal(cx, obj, JSVAL_TO_OBJECT(arg));
    4391                 : }
    4392                 : 
    4393                 : JSBool
    4394               0 : StructType::ConstructData(JSContext* cx,
    4395                 :                           JSObject* obj,
    4396                 :                           unsigned argc,
    4397                 :                           jsval* vp)
    4398                 : {
    4399               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_struct) {
    4400               0 :     JS_ReportError(cx, "not a StructType");
    4401               0 :     return JS_FALSE;
    4402                 :   }
    4403                 : 
    4404               0 :   if (!CType::IsSizeDefined(obj)) {
    4405               0 :     JS_ReportError(cx, "cannot construct an opaque StructType");
    4406               0 :     return JS_FALSE;
    4407                 :   }
    4408                 : 
    4409               0 :   JSObject* result = CData::Create(cx, obj, NULL, NULL, true);
    4410               0 :   if (!result)
    4411               0 :     return JS_FALSE;
    4412                 : 
    4413               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    4414                 : 
    4415               0 :   if (argc == 0)
    4416               0 :     return JS_TRUE;
    4417                 : 
    4418               0 :   char* buffer = static_cast<char*>(CData::GetData(result));
    4419               0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    4420                 : 
    4421               0 :   jsval* argv = JS_ARGV(cx, vp);
    4422               0 :   if (argc == 1) {
    4423                 :     // There are two possible interpretations of the argument:
    4424                 :     // 1) It may be an object '{ ... }' with properties representing the
    4425                 :     //    struct fields intended to ExplicitConvert wholesale to our StructType.
    4426                 :     // 2) If the struct contains one field, the arg may be intended to
    4427                 :     //    ImplicitConvert directly to that arg's CType.
    4428                 :     // Thankfully, the conditions for these two possibilities to succeed
    4429                 :     // are mutually exclusive, so we can pick the right one.
    4430                 : 
    4431                 :     // Try option 1) first.
    4432               0 :     if (ExplicitConvert(cx, argv[0], obj, buffer))
    4433               0 :       return JS_TRUE;
    4434                 : 
    4435               0 :     if (fields->count() != 1)
    4436               0 :       return JS_FALSE;
    4437                 : 
    4438                 :     // If ExplicitConvert failed, and there is no pending exception, then assume
    4439                 :     // hard failure (out of memory, or some other similarly serious condition).
    4440               0 :     if (!JS_IsExceptionPending(cx))
    4441               0 :       return JS_FALSE;
    4442                 : 
    4443                 :     // Otherwise, assume soft failure, and clear the pending exception so that we
    4444                 :     // can throw a different one as required.
    4445               0 :     JS_ClearPendingException(cx);
    4446                 : 
    4447                 :     // Fall through to try option 2).
    4448                 :   }
    4449                 : 
    4450                 :   // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'.
    4451                 :   // ImplicitConvert each field.
    4452               0 :   if (argc == fields->count()) {
    4453               0 :     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    4454               0 :       const FieldInfo& field = r.front().value;
    4455                 :       STATIC_ASSUME(field.mIndex < fields->count());  /* Quantified invariant */
    4456               0 :       if (!ImplicitConvert(cx, argv[field.mIndex], field.mType,
    4457               0 :              buffer + field.mOffset,
    4458               0 :              false, NULL))
    4459               0 :         return JS_FALSE;
    4460                 :     }
    4461                 : 
    4462               0 :     return JS_TRUE;
    4463                 :   }
    4464                 : 
    4465                 :   JS_ReportError(cx, "constructor takes 0, 1, or %u arguments",
    4466               0 :     fields->count());
    4467               0 :   return JS_FALSE;
    4468                 : }
    4469                 : 
    4470                 : const FieldInfoHash*
    4471               0 : StructType::GetFieldInfo(JSObject* obj)
    4472                 : {
    4473               0 :   JS_ASSERT(CType::IsCType(obj));
    4474               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    4475                 : 
    4476               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
    4477               0 :   JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
    4478                 : 
    4479               0 :   return static_cast<const FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
    4480                 : }
    4481                 : 
    4482                 : const FieldInfo*
    4483               0 : StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
    4484                 : {
    4485               0 :   JS_ASSERT(CType::IsCType(obj));
    4486               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    4487                 : 
    4488               0 :   FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name);
    4489               0 :   if (ptr)
    4490               0 :     return &ptr->value;
    4491                 : 
    4492               0 :   JSAutoByteString bytes(cx, name);
    4493               0 :   if (!bytes)
    4494               0 :     return NULL;
    4495                 : 
    4496               0 :   JS_ReportError(cx, "%s does not name a field", bytes.ptr());
    4497               0 :   return NULL;
    4498                 : }
    4499                 : 
    4500                 : JSObject*
    4501               0 : StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
    4502                 : {
    4503               0 :   JS_ASSERT(CType::IsCType(obj));
    4504               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
    4505               0 :   JS_ASSERT(CType::IsSizeDefined(obj));
    4506                 : 
    4507               0 :   const FieldInfoHash* fields = GetFieldInfo(obj);
    4508               0 :   size_t len = fields->count();
    4509                 : 
    4510                 :   // Prepare a new array for the 'fields' property of the StructType.
    4511               0 :   Array<jsval, 16> fieldsVec;
    4512               0 :   if (!fieldsVec.appendN(JSVAL_VOID, len))
    4513               0 :     return NULL;
    4514               0 :   js::AutoArrayRooter root(cx, fieldsVec.length(), fieldsVec.begin());
    4515                 : 
    4516               0 :   for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
    4517               0 :     const FieldInfoHash::Entry& entry = r.front();
    4518                 :     // Add the field descriptor to the array.
    4519               0 :     if (!AddFieldToArray(cx, &fieldsVec[entry.value.mIndex],
    4520               0 :                          entry.key, entry.value.mType))
    4521               0 :       return NULL;
    4522                 :   }
    4523                 : 
    4524               0 :   JSObject* fieldsProp = JS_NewArrayObject(cx, len, fieldsVec.begin());
    4525               0 :   if (!fieldsProp)
    4526               0 :     return NULL;
    4527                 : 
    4528                 :   // Seal the fields array.
    4529               0 :   if (!JS_FreezeObject(cx, fieldsProp))
    4530               0 :     return NULL;
    4531                 : 
    4532               0 :   return fieldsProp;
    4533                 : }
    4534                 : 
    4535                 : JSBool
    4536               0 : StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    4537                 : {
    4538               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_struct) {
    4539               0 :     JS_ReportError(cx, "not a StructType");
    4540               0 :     return JS_FALSE;
    4541                 :   }
    4542                 : 
    4543               0 :   *vp = JS_GetReservedSlot(obj, SLOT_FIELDS);
    4544                 : 
    4545               0 :   if (!CType::IsSizeDefined(obj)) {
    4546               0 :     JS_ASSERT(JSVAL_IS_VOID(*vp));
    4547               0 :     return JS_TRUE;
    4548                 :   }
    4549                 : 
    4550               0 :   if (JSVAL_IS_VOID(*vp)) {
    4551                 :     // Build the 'fields' array lazily.
    4552               0 :     JSObject* fields = BuildFieldsArray(cx, obj);
    4553               0 :     if (!fields)
    4554               0 :       return JS_FALSE;
    4555               0 :     JS_SetReservedSlot(obj, SLOT_FIELDS, OBJECT_TO_JSVAL(fields));
    4556                 : 
    4557               0 :     *vp = OBJECT_TO_JSVAL(fields);
    4558                 :   }
    4559                 : 
    4560               0 :   JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp) &&
    4561               0 :             JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*vp)));
    4562               0 :   return JS_TRUE;
    4563                 : }
    4564                 : 
    4565                 : JSBool
    4566               0 : StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    4567                 : {
    4568               0 :   if (!CData::IsCData(obj)) {
    4569               0 :     JS_ReportError(cx, "not a CData");
    4570               0 :     return JS_FALSE;
    4571                 :   }
    4572                 : 
    4573               0 :   JSObject* typeObj = CData::GetCType(obj);
    4574               0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    4575               0 :     JS_ReportError(cx, "not a StructType");
    4576               0 :     return JS_FALSE;
    4577                 :   }
    4578                 : 
    4579               0 :   const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
    4580               0 :   if (!field)
    4581               0 :     return JS_FALSE;
    4582                 : 
    4583               0 :   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    4584               0 :   return ConvertToJS(cx, field->mType, obj, data, false, false, vp);
    4585                 : }
    4586                 : 
    4587                 : JSBool
    4588               0 : StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp)
    4589                 : {
    4590               0 :   if (!CData::IsCData(obj)) {
    4591               0 :     JS_ReportError(cx, "not a CData");
    4592               0 :     return JS_FALSE;
    4593                 :   }
    4594                 : 
    4595               0 :   JSObject* typeObj = CData::GetCType(obj);
    4596               0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    4597               0 :     JS_ReportError(cx, "not a StructType");
    4598               0 :     return JS_FALSE;
    4599                 :   }
    4600                 : 
    4601               0 :   const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
    4602               0 :   if (!field)
    4603               0 :     return JS_FALSE;
    4604                 : 
    4605               0 :   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    4606               0 :   return ImplicitConvert(cx, *vp, field->mType, data, false, NULL);
    4607                 : }
    4608                 : 
    4609                 : JSBool
    4610               0 : StructType::AddressOfField(JSContext* cx, unsigned argc, jsval* vp)
    4611                 : {
    4612               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    4613               0 :   if (!obj || !CData::IsCData(obj)) {
    4614               0 :     JS_ReportError(cx, "not a CData");
    4615               0 :     return JS_FALSE;
    4616                 :   }
    4617                 : 
    4618               0 :   JSObject* typeObj = CData::GetCType(obj);
    4619               0 :   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
    4620               0 :     JS_ReportError(cx, "not a StructType");
    4621               0 :     return JS_FALSE;
    4622                 :   }
    4623                 : 
    4624               0 :   if (argc != 1) {
    4625               0 :     JS_ReportError(cx, "addressOfField takes one argument");
    4626               0 :     return JS_FALSE;
    4627                 :   }
    4628                 : 
    4629               0 :   JSFlatString *str = JS_FlattenString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
    4630               0 :   if (!str)
    4631               0 :     return JS_FALSE;
    4632                 : 
    4633               0 :   const FieldInfo* field = LookupField(cx, typeObj, str);
    4634               0 :   if (!field)
    4635               0 :     return JS_FALSE;
    4636                 : 
    4637               0 :   JSObject* baseType = field->mType;
    4638               0 :   JSObject* pointerType = PointerType::CreateInternal(cx, baseType);
    4639               0 :   if (!pointerType)
    4640               0 :     return JS_FALSE;
    4641               0 :   js::AutoObjectRooter root(cx, pointerType);
    4642                 : 
    4643                 :   // Create a PointerType CData object containing null.
    4644               0 :   JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true);
    4645               0 :   if (!result)
    4646               0 :     return JS_FALSE;
    4647                 : 
    4648               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    4649                 : 
    4650                 :   // Manually set the pointer inside the object, so we skip the conversion step.
    4651               0 :   void** data = static_cast<void**>(CData::GetData(result));
    4652               0 :   *data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
    4653               0 :   return JS_TRUE;
    4654                 : }
    4655                 : 
    4656                 : /*******************************************************************************
    4657                 : ** FunctionType implementation
    4658                 : *******************************************************************************/
    4659                 : 
    4660                 : // Helper class for handling allocation of function arguments.
    4661                 : struct AutoValue
    4662                 : {
    4663               0 :   AutoValue() : mData(NULL) { }
    4664                 : 
    4665               0 :   ~AutoValue()
    4666                 :   {
    4667               0 :     UnwantedForeground::array_delete(static_cast<char*>(mData));
    4668               0 :   }
    4669                 : 
    4670               0 :   bool SizeToType(JSContext* cx, JSObject* type)
    4671                 :   {
    4672                 :     // Allocate a minimum of sizeof(ffi_arg) to handle small integers.
    4673               0 :     size_t size = Align(CType::GetSize(type), sizeof(ffi_arg));
    4674               0 :     mData = cx->array_new<char>(size);
    4675               0 :     if (mData)
    4676               0 :       memset(mData, 0, size);
    4677               0 :     return mData != NULL;
    4678                 :   }
    4679                 : 
    4680                 :   void* mData;
    4681                 : };
    4682                 : 
    4683                 : static bool
    4684               0 : GetABI(JSContext* cx, jsval abiType, ffi_abi* result)
    4685                 : {
    4686               0 :   if (JSVAL_IS_PRIMITIVE(abiType))
    4687               0 :     return false;
    4688                 : 
    4689               0 :   ABICode abi = GetABICode(JSVAL_TO_OBJECT(abiType));
    4690                 : 
    4691                 :   // determine the ABI from the subset of those available on the
    4692                 :   // given platform. ABI_DEFAULT specifies the default
    4693                 :   // C calling convention (cdecl) on each platform.
    4694               0 :   switch (abi) {
    4695                 :   case ABI_DEFAULT:
    4696               0 :     *result = FFI_DEFAULT_ABI;
    4697               0 :     return true;
    4698                 :   case ABI_STDCALL:
    4699                 :   case ABI_WINAPI:
    4700                 : #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
    4701                 :     *result = FFI_STDCALL;
    4702                 :     return true;
    4703                 : #elif (defined(_WIN64))
    4704                 :     // We'd like the same code to work across Win32 and Win64, so stdcall_api
    4705                 :     // and winapi_abi become aliases to the lone Win64 ABI.
    4706                 :     *result = FFI_WIN64;
    4707                 :     return true;
    4708                 : #endif
    4709                 :   case INVALID_ABI:
    4710                 :     break;
    4711                 :   }
    4712               0 :   return false;
    4713                 : }
    4714                 : 
    4715                 : static JSObject*
    4716               0 : PrepareType(JSContext* cx, jsval type)
    4717                 : {
    4718               0 :   if (JSVAL_IS_PRIMITIVE(type) ||
    4719               0 :       !CType::IsCType(JSVAL_TO_OBJECT(type))) {
    4720               0 :     JS_ReportError(cx, "not a ctypes type");
    4721               0 :     return NULL;
    4722                 :   }
    4723                 : 
    4724               0 :   JSObject* result = JSVAL_TO_OBJECT(type);
    4725               0 :   TypeCode typeCode = CType::GetTypeCode(result);
    4726                 : 
    4727               0 :   if (typeCode == TYPE_array) {
    4728                 :     // convert array argument types to pointers, just like C.
    4729                 :     // ImplicitConvert will do the same, when passing an array as data.
    4730               0 :     JSObject* baseType = ArrayType::GetBaseType(result);
    4731               0 :     result = PointerType::CreateInternal(cx, baseType);
    4732               0 :     if (!result)
    4733               0 :       return NULL;
    4734                 : 
    4735               0 :   } else if (typeCode == TYPE_void_t || typeCode == TYPE_function) {
    4736                 :     // disallow void or function argument types
    4737               0 :     JS_ReportError(cx, "Cannot have void or function argument type");
    4738               0 :     return NULL;
    4739                 :   }
    4740                 : 
    4741               0 :   if (!CType::IsSizeDefined(result)) {
    4742               0 :     JS_ReportError(cx, "Argument type must have defined size");
    4743               0 :     return NULL;
    4744                 :   }
    4745                 : 
    4746                 :   // libffi cannot pass types of zero size by value.
    4747               0 :   JS_ASSERT(CType::GetSize(result) != 0);
    4748                 : 
    4749               0 :   return result;
    4750                 : }
    4751                 : 
    4752                 : static JSObject*
    4753               0 : PrepareReturnType(JSContext* cx, jsval type)
    4754                 : {
    4755               0 :   if (JSVAL_IS_PRIMITIVE(type) ||
    4756               0 :       !CType::IsCType(JSVAL_TO_OBJECT(type))) {
    4757               0 :     JS_ReportError(cx, "not a ctypes type");
    4758               0 :     return NULL;
    4759                 :   }
    4760                 : 
    4761               0 :   JSObject* result = JSVAL_TO_OBJECT(type);
    4762               0 :   TypeCode typeCode = CType::GetTypeCode(result);
    4763                 : 
    4764                 :   // Arrays and functions can never be return types.
    4765               0 :   if (typeCode == TYPE_array || typeCode == TYPE_function) {
    4766               0 :     JS_ReportError(cx, "Return type cannot be an array or function");
    4767               0 :     return NULL;
    4768                 :   }
    4769                 : 
    4770               0 :   if (typeCode != TYPE_void_t && !CType::IsSizeDefined(result)) {
    4771               0 :     JS_ReportError(cx, "Return type must have defined size");
    4772               0 :     return NULL;
    4773                 :   }
    4774                 : 
    4775                 :   // libffi cannot pass types of zero size by value.
    4776               0 :   JS_ASSERT(typeCode == TYPE_void_t || CType::GetSize(result) != 0);
    4777                 : 
    4778               0 :   return result;
    4779                 : }
    4780                 : 
    4781                 : static JS_ALWAYS_INLINE JSBool
    4782               0 : IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
    4783                 : {
    4784               0 :   *isEllipsis = false;
    4785               0 :   if (!JSVAL_IS_STRING(v))
    4786               0 :     return true;
    4787               0 :   JSString* str = JSVAL_TO_STRING(v);
    4788               0 :   if (str->length() != 3)
    4789               0 :     return true;
    4790               0 :   const jschar* chars = str->getChars(cx);
    4791               0 :   if (!chars)
    4792               0 :     return false;
    4793               0 :   jschar dot = '.';
    4794               0 :   *isEllipsis = (chars[0] == dot &&
    4795               0 :                  chars[1] == dot &&
    4796               0 :                  chars[2] == dot);
    4797               0 :   return true;
    4798                 : }
    4799                 : 
    4800                 : static JSBool
    4801               0 : PrepareCIF(JSContext* cx,
    4802                 :            FunctionInfo* fninfo)
    4803                 : {
    4804                 :   ffi_abi abi;
    4805               0 :   if (!GetABI(cx, OBJECT_TO_JSVAL(fninfo->mABI), &abi)) {
    4806               0 :     JS_ReportError(cx, "Invalid ABI specification");
    4807               0 :     return false;
    4808                 :   }
    4809                 : 
    4810               0 :   ffi_type* rtype = CType::GetFFIType(cx, fninfo->mReturnType);
    4811               0 :   if (!rtype)
    4812               0 :     return false;
    4813                 : 
    4814                 :   ffi_status status =
    4815                 :     ffi_prep_cif(&fninfo->mCIF,
    4816                 :                  abi,
    4817                 :                  fninfo->mFFITypes.length(),
    4818                 :                  rtype,
    4819               0 :                  fninfo->mFFITypes.begin());
    4820                 : 
    4821               0 :   switch (status) {
    4822                 :   case FFI_OK:
    4823               0 :     return true;
    4824                 :   case FFI_BAD_ABI:
    4825               0 :     JS_ReportError(cx, "Invalid ABI specification");
    4826               0 :     return false;
    4827                 :   case FFI_BAD_TYPEDEF:
    4828               0 :     JS_ReportError(cx, "Invalid type specification");
    4829               0 :     return false;
    4830                 :   default:
    4831               0 :     JS_ReportError(cx, "Unknown libffi error");
    4832               0 :     return false;
    4833                 :   }
    4834                 : }
    4835                 : 
    4836                 : void
    4837               0 : FunctionType::BuildSymbolName(JSString* name,
    4838                 :                               JSObject* typeObj,
    4839                 :                               AutoCString& result)
    4840                 : {
    4841               0 :   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
    4842                 : 
    4843               0 :   switch (GetABICode(fninfo->mABI)) {
    4844                 :   case ABI_DEFAULT:
    4845                 :   case ABI_WINAPI:
    4846                 :     // For cdecl or WINAPI functions, no mangling is necessary.
    4847               0 :     AppendString(result, name);
    4848               0 :     break;
    4849                 : 
    4850                 :   case ABI_STDCALL: {
    4851                 : #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
    4852                 :     // On WIN32, stdcall functions look like:
    4853                 :     //   _foo@40
    4854                 :     // where 'foo' is the function name, and '40' is the aligned size of the
    4855                 :     // arguments.
    4856                 :     AppendString(result, "_");
    4857                 :     AppendString(result, name);
    4858                 :     AppendString(result, "@");
    4859                 : 
    4860                 :     // Compute the suffix by aligning each argument to sizeof(ffi_arg).
    4861                 :     size_t size = 0;
    4862                 :     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
    4863                 :       JSObject* argType = fninfo->mArgTypes[i];
    4864                 :       size += Align(CType::GetSize(argType), sizeof(ffi_arg));
    4865                 :     }
    4866                 : 
    4867                 :     IntegerToString(size, 10, result);
    4868                 : #elif defined(_WIN64)
    4869                 :     // On Win64, stdcall is an alias to the default ABI for compatibility, so no
    4870                 :     // mangling is done.
    4871                 :     AppendString(result, name);
    4872                 : #endif
    4873               0 :     break;
    4874                 :   }
    4875                 : 
    4876                 :   case INVALID_ABI:
    4877               0 :     JS_NOT_REACHED("invalid abi");
    4878                 :     break;
    4879                 :   }
    4880               0 : }
    4881                 : 
    4882                 : static FunctionInfo*
    4883               0 : NewFunctionInfo(JSContext* cx,
    4884                 :                 jsval abiType,
    4885                 :                 jsval returnType,
    4886                 :                 jsval* argTypes,
    4887                 :                 unsigned argLength)
    4888                 : {
    4889               0 :   AutoPtr<FunctionInfo> fninfo(cx->new_<FunctionInfo>());
    4890               0 :   if (!fninfo) {
    4891               0 :     JS_ReportOutOfMemory(cx);
    4892               0 :     return NULL;
    4893                 :   }
    4894                 : 
    4895                 :   ffi_abi abi;
    4896               0 :   if (!GetABI(cx, abiType, &abi)) {
    4897               0 :     JS_ReportError(cx, "Invalid ABI specification");
    4898               0 :     return NULL;
    4899                 :   }
    4900               0 :   fninfo->mABI = JSVAL_TO_OBJECT(abiType);
    4901                 : 
    4902                 :   // prepare the result type
    4903               0 :   fninfo->mReturnType = PrepareReturnType(cx, returnType);
    4904               0 :   if (!fninfo->mReturnType)
    4905               0 :     return NULL;
    4906                 : 
    4907                 :   // prepare the argument types
    4908               0 :   if (!fninfo->mArgTypes.reserve(argLength) ||
    4909               0 :       !fninfo->mFFITypes.reserve(argLength)) {
    4910               0 :     JS_ReportOutOfMemory(cx);
    4911               0 :     return NULL;
    4912                 :   }
    4913                 : 
    4914               0 :   fninfo->mIsVariadic = false;
    4915                 : 
    4916               0 :   for (uint32_t i = 0; i < argLength; ++i) {
    4917                 :     bool isEllipsis;
    4918               0 :     if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
    4919               0 :       return NULL;
    4920               0 :     if (isEllipsis) {
    4921               0 :       fninfo->mIsVariadic = true;
    4922               0 :       if (i < 1) {
    4923                 :         JS_ReportError(cx, "\"...\" may not be the first and only parameter "
    4924               0 :                        "type of a variadic function declaration");
    4925               0 :         return NULL;
    4926                 :       }
    4927               0 :       if (i < argLength - 1) {
    4928                 :         JS_ReportError(cx, "\"...\" must be the last parameter type of a "
    4929               0 :                        "variadic function declaration");
    4930               0 :         return NULL;
    4931                 :       }
    4932               0 :       if (GetABICode(fninfo->mABI) != ABI_DEFAULT) {
    4933                 :         JS_ReportError(cx, "Variadic functions must use the __cdecl calling "
    4934               0 :                        "convention");
    4935               0 :         return NULL;
    4936                 :       }
    4937               0 :       break;
    4938                 :     }
    4939                 : 
    4940               0 :     JSObject* argType = PrepareType(cx, argTypes[i]);
    4941               0 :     if (!argType)
    4942               0 :       return NULL;
    4943                 : 
    4944               0 :     ffi_type* ffiType = CType::GetFFIType(cx, argType);
    4945               0 :     if (!ffiType)
    4946               0 :       return NULL;
    4947                 : 
    4948               0 :     fninfo->mArgTypes.infallibleAppend(argType);
    4949               0 :     fninfo->mFFITypes.infallibleAppend(ffiType);
    4950                 :   }
    4951                 : 
    4952               0 :   if (fninfo->mIsVariadic)
    4953                 :     // wait to PrepareCIF until function is called
    4954               0 :     return fninfo.forget();
    4955                 : 
    4956               0 :   if (!PrepareCIF(cx, fninfo.get()))
    4957               0 :     return NULL;
    4958                 : 
    4959               0 :   return fninfo.forget();
    4960                 : }
    4961                 : 
    4962                 : JSBool
    4963               0 : FunctionType::Create(JSContext* cx, unsigned argc, jsval* vp)
    4964                 : {
    4965                 :   // Construct and return a new FunctionType object.
    4966               0 :   if (argc < 2 || argc > 3) {
    4967               0 :     JS_ReportError(cx, "FunctionType takes two or three arguments");
    4968               0 :     return JS_FALSE;
    4969                 :   }
    4970                 : 
    4971               0 :   jsval* argv = JS_ARGV(cx, vp);
    4972               0 :   Array<jsval, 16> argTypes;
    4973               0 :   JSObject* arrayObj = NULL;
    4974                 : 
    4975               0 :   if (argc == 3) {
    4976                 :     // Prepare an array of jsvals for the arguments.
    4977               0 :     if (JSVAL_IS_PRIMITIVE(argv[2]) ||
    4978               0 :         !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[2]))) {
    4979               0 :       JS_ReportError(cx, "third argument must be an array");
    4980               0 :       return JS_FALSE;
    4981                 :     }
    4982                 : 
    4983               0 :     arrayObj = JSVAL_TO_OBJECT(argv[2]);
    4984                 :     uint32_t len;
    4985               0 :     ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len));
    4986                 : 
    4987               0 :     if (!argTypes.appendN(JSVAL_VOID, len)) {
    4988               0 :       JS_ReportOutOfMemory(cx);
    4989               0 :       return JS_FALSE;
    4990                 :     }
    4991                 :   }
    4992                 : 
    4993                 :   // Pull out the argument types from the array, if any.
    4994               0 :   JS_ASSERT(!argTypes.length() || arrayObj);
    4995               0 :   js::AutoArrayRooter items(cx, argTypes.length(), argTypes.begin());
    4996               0 :   for (uint32_t i = 0; i < argTypes.length(); ++i) {
    4997               0 :     if (!JS_GetElement(cx, arrayObj, i, &argTypes[i]))
    4998               0 :       return JS_FALSE;
    4999                 :   }
    5000                 : 
    5001               0 :   JSObject* result = CreateInternal(cx, argv[0], argv[1],
    5002               0 :       argTypes.begin(), argTypes.length());
    5003               0 :   if (!result)
    5004               0 :     return JS_FALSE;
    5005                 : 
    5006               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    5007               0 :   return JS_TRUE;
    5008                 : }
    5009                 : 
    5010                 : JSObject*
    5011               0 : FunctionType::CreateInternal(JSContext* cx,
    5012                 :                              jsval abi,
    5013                 :                              jsval rtype,
    5014                 :                              jsval* argtypes,
    5015                 :                              unsigned arglen)
    5016                 : {
    5017                 :   // Determine and check the types, and prepare the function CIF.
    5018               0 :   AutoPtr<FunctionInfo> fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen));
    5019               0 :   if (!fninfo)
    5020               0 :     return NULL;
    5021                 : 
    5022                 :   // Get ctypes.FunctionType.prototype and the common prototype for CData objects
    5023                 :   // of this type, from ctypes.CType.prototype.
    5024               0 :   JSObject* typeProto = CType::GetProtoFromType(fninfo->mReturnType,
    5025               0 :                                                 SLOT_FUNCTIONPROTO);
    5026               0 :   JSObject* dataProto = CType::GetProtoFromType(fninfo->mReturnType,
    5027               0 :                                                 SLOT_FUNCTIONDATAPROTO);
    5028                 : 
    5029                 :   // Create a new CType object with the common properties and slots.
    5030                 :   JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_function,
    5031               0 :                         NULL, JSVAL_VOID, JSVAL_VOID, NULL);
    5032               0 :   if (!typeObj)
    5033               0 :     return NULL;
    5034               0 :   js::AutoObjectRooter root(cx, typeObj);
    5035                 : 
    5036                 :   // Stash the FunctionInfo in a reserved slot.
    5037               0 :   JS_SetReservedSlot(typeObj, SLOT_FNINFO, PRIVATE_TO_JSVAL(fninfo.forget()));
    5038                 : 
    5039               0 :   return typeObj;
    5040                 : }
    5041                 : 
    5042                 : // Construct a function pointer to a JS function (see CClosure::Create()).
    5043                 : // Regular function pointers are constructed directly in
    5044                 : // PointerType::ConstructData().
    5045                 : JSBool
    5046               0 : FunctionType::ConstructData(JSContext* cx,
    5047                 :                             JSObject* typeObj,
    5048                 :                             JSObject* dataObj,
    5049                 :                             JSObject* fnObj,
    5050                 :                             JSObject* thisObj,
    5051                 :                             jsval errVal)
    5052                 : {
    5053               0 :   JS_ASSERT(CType::GetTypeCode(typeObj) == TYPE_function);
    5054                 : 
    5055               0 :   PRFuncPtr* data = static_cast<PRFuncPtr*>(CData::GetData(dataObj));
    5056                 : 
    5057               0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    5058               0 :   if (fninfo->mIsVariadic) {
    5059               0 :     JS_ReportError(cx, "Can't declare a variadic callback function");
    5060               0 :     return JS_FALSE;
    5061                 :   }
    5062               0 :   if (GetABICode(fninfo->mABI) == ABI_WINAPI) {
    5063                 :     JS_ReportError(cx, "Can't declare a ctypes.winapi_abi callback function, "
    5064               0 :                    "use ctypes.stdcall_abi instead");
    5065               0 :     return JS_FALSE;
    5066                 :   }
    5067                 : 
    5068               0 :   JSObject* closureObj = CClosure::Create(cx, typeObj, fnObj, thisObj, errVal, data);
    5069               0 :   if (!closureObj)
    5070               0 :     return JS_FALSE;
    5071               0 :   js::AutoObjectRooter root(cx, closureObj);
    5072                 : 
    5073                 :   // Set the closure object as the referent of the new CData object.
    5074               0 :   JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(closureObj));
    5075                 : 
    5076                 :   // Seal the CData object, to prevent modification of the function pointer.
    5077                 :   // This permanently associates this object with the closure, and avoids
    5078                 :   // having to do things like reset SLOT_REFERENT when someone tries to
    5079                 :   // change the pointer value.
    5080                 :   // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
    5081                 :   // could be called on a frozen object.
    5082               0 :   return JS_FreezeObject(cx, dataObj);
    5083                 : }
    5084                 : 
    5085                 : typedef Array<AutoValue, 16> AutoValueAutoArray;
    5086                 : 
    5087                 : static JSBool
    5088               0 : ConvertArgument(JSContext* cx,
    5089                 :                 jsval arg,
    5090                 :                 JSObject* type,
    5091                 :                 AutoValue* value,
    5092                 :                 AutoValueAutoArray* strings)
    5093                 : {
    5094               0 :   if (!value->SizeToType(cx, type)) {
    5095               0 :     JS_ReportAllocationOverflow(cx);
    5096               0 :     return false;
    5097                 :   }
    5098                 : 
    5099               0 :   bool freePointer = false;
    5100               0 :   if (!ImplicitConvert(cx, arg, type, value->mData, true, &freePointer))
    5101               0 :     return false;
    5102                 : 
    5103               0 :   if (freePointer) {
    5104                 :     // ImplicitConvert converted a string for us, which we have to free.
    5105                 :     // Keep track of it.
    5106               0 :     if (!strings->growBy(1)) {
    5107               0 :       JS_ReportOutOfMemory(cx);
    5108               0 :       return false;
    5109                 :     }
    5110               0 :     strings->back().mData = *static_cast<char**>(value->mData);
    5111                 :   }
    5112                 : 
    5113               0 :   return true;
    5114                 : }
    5115                 : 
    5116                 : JSBool
    5117               0 : FunctionType::Call(JSContext* cx,
    5118                 :                    unsigned argc,
    5119                 :                    jsval* vp)
    5120                 : {
    5121                 :   // get the callee object...
    5122               0 :   JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
    5123               0 :   if (!CData::IsCData(obj)) {
    5124               0 :     JS_ReportError(cx, "not a CData");
    5125               0 :     return false;
    5126                 :   }
    5127                 : 
    5128               0 :   JSObject* typeObj = CData::GetCType(obj);
    5129               0 :   if (CType::GetTypeCode(typeObj) != TYPE_pointer) {
    5130               0 :     JS_ReportError(cx, "not a FunctionType.ptr");
    5131               0 :     return false;
    5132                 :   }
    5133                 : 
    5134               0 :   typeObj = PointerType::GetBaseType(typeObj);
    5135               0 :   if (CType::GetTypeCode(typeObj) != TYPE_function) {
    5136               0 :     JS_ReportError(cx, "not a FunctionType.ptr");
    5137               0 :     return false;
    5138                 :   }
    5139                 : 
    5140               0 :   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
    5141               0 :   uint32_t argcFixed = fninfo->mArgTypes.length();
    5142                 : 
    5143               0 :   if ((!fninfo->mIsVariadic && argc != argcFixed) ||
    5144                 :       (fninfo->mIsVariadic && argc < argcFixed)) {
    5145               0 :     JS_ReportError(cx, "Number of arguments does not match declaration");
    5146               0 :     return false;
    5147                 :   }
    5148                 : 
    5149                 :   // Check if we have a Library object. If we do, make sure it's open.
    5150               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_REFERENT);
    5151               0 :   if (!JSVAL_IS_VOID(slot) && Library::IsLibrary(JSVAL_TO_OBJECT(slot))) {
    5152               0 :     PRLibrary* library = Library::GetLibrary(JSVAL_TO_OBJECT(slot));
    5153               0 :     if (!library) {
    5154               0 :       JS_ReportError(cx, "library is not open");
    5155               0 :       return false;
    5156                 :     }
    5157                 :   }
    5158                 : 
    5159                 :   // prepare the values for each argument
    5160               0 :   AutoValueAutoArray values;
    5161               0 :   AutoValueAutoArray strings;
    5162               0 :   if (!values.resize(argc)) {
    5163               0 :     JS_ReportOutOfMemory(cx);
    5164               0 :     return false;
    5165                 :   }
    5166                 : 
    5167               0 :   jsval* argv = JS_ARGV(cx, vp);
    5168               0 :   for (unsigned i = 0; i < argcFixed; ++i)
    5169               0 :     if (!ConvertArgument(cx, argv[i], fninfo->mArgTypes[i], &values[i], &strings))
    5170               0 :       return false;
    5171                 : 
    5172               0 :   if (fninfo->mIsVariadic) {
    5173               0 :     if (!fninfo->mFFITypes.resize(argc)) {
    5174               0 :       JS_ReportOutOfMemory(cx);
    5175               0 :       return false;
    5176                 :     }
    5177                 : 
    5178                 :     JSObject* obj;  // Could reuse obj instead of declaring a second
    5179                 :     JSObject* type; // JSObject*, but readability would suffer.
    5180                 : 
    5181               0 :     for (uint32_t i = argcFixed; i < argc; ++i) {
    5182               0 :       if (JSVAL_IS_PRIMITIVE(argv[i]) ||
    5183               0 :           !CData::IsCData(obj = JSVAL_TO_OBJECT(argv[i]))) {
    5184                 :         // Since we know nothing about the CTypes of the ... arguments,
    5185                 :         // they absolutely must be CData objects already.
    5186                 :         JS_ReportError(cx, "argument %d of type %s is not a CData object",
    5187               0 :                        i, JS_GetTypeName(cx, JS_TypeOfValue(cx, argv[i])));
    5188               0 :         return false;
    5189                 :       }
    5190               0 :       if (!(type = CData::GetCType(obj)) ||
    5191               0 :           !(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) ||
    5192                 :           // Relying on ImplicitConvert only for the limited purpose of
    5193                 :           // converting one CType to another (e.g., T[] to T*).
    5194               0 :           !ConvertArgument(cx, argv[i], type, &values[i], &strings) ||
    5195               0 :           !(fninfo->mFFITypes[i] = CType::GetFFIType(cx, type))) {
    5196                 :         // These functions report their own errors.
    5197               0 :         return false;
    5198                 :       }
    5199                 :     }
    5200               0 :     if (!PrepareCIF(cx, fninfo))
    5201               0 :       return false;
    5202                 :   }
    5203                 : 
    5204                 :   // initialize a pointer to an appropriate location, for storing the result
    5205               0 :   AutoValue returnValue;
    5206               0 :   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
    5207               0 :   if (typeCode != TYPE_void_t &&
    5208               0 :       !returnValue.SizeToType(cx, fninfo->mReturnType)) {
    5209               0 :     JS_ReportAllocationOverflow(cx);
    5210               0 :     return false;
    5211                 :   }
    5212                 : 
    5213               0 :   uintptr_t fn = *reinterpret_cast<uintptr_t*>(CData::GetData(obj));
    5214                 : 
    5215                 : #if defined(XP_WIN)
    5216                 :   int32_t lastErrorStatus; // The status as defined by |GetLastError|
    5217                 :   int32_t savedLastError = GetLastError();
    5218                 :   SetLastError(0);
    5219                 : #endif //defined(XP_WIN)
    5220                 :   int errnoStatus;         // The status as defined by |errno|
    5221               0 :   int savedErrno = errno;
    5222               0 :   errno = 0;
    5223                 : 
    5224                 :   // suspend the request before we call into the function, since the call
    5225                 :   // may block or otherwise take a long time to return.
    5226                 :   {
    5227               0 :     JSAutoSuspendRequest suspend(cx);
    5228                 :     ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData,
    5229               0 :              reinterpret_cast<void**>(values.begin()));
    5230                 : 
    5231                 :     // Save error value.
    5232                 :     // We need to save it before leaving the scope of |suspend| as destructing
    5233                 :     // |suspend| has the side-effect of clearing |GetLastError|
    5234                 :     // (see bug 684017).
    5235                 : 
    5236               0 :     errnoStatus = errno;
    5237                 : #if defined(XP_WIN)
    5238                 :     lastErrorStatus = GetLastError();
    5239                 : #endif // defined(XP_WIN)
    5240                 :   }
    5241                 : #if defined(XP_WIN)
    5242                 :   SetLastError(savedLastError);
    5243                 : #endif // defined(XP_WIN)
    5244                 : 
    5245               0 :   errno = savedErrno;
    5246                 : 
    5247                 :   // Store the error value for later consultation with |ctypes.getStatus|
    5248               0 :   JSObject *objCTypes = CType::GetGlobalCTypes(cx, typeObj);
    5249                 : 
    5250               0 :   JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus));
    5251                 : #if defined(XP_WIN)
    5252                 :   JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus));
    5253                 : #endif // defined(XP_WIN)
    5254                 : 
    5255                 :   // Small integer types get returned as a word-sized ffi_arg. Coerce it back
    5256                 :   // into the correct size for ConvertToJS.
    5257               0 :   switch (typeCode) {
    5258                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    5259                 :   case TYPE_##name:                                                            \
    5260                 :     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
    5261                 :       ffi_arg data = *static_cast<ffi_arg*>(returnValue.mData);                \
    5262                 :       *static_cast<type*>(returnValue.mData) = static_cast<type>(data);        \
    5263                 :     }                                                                          \
    5264                 :     break;
    5265                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5266                 : #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5267                 : #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5268                 : #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5269                 : #include "typedefs.h"
    5270                 :   default:
    5271               0 :     break;
    5272                 :   }
    5273                 : 
    5274                 :   // prepare a JS object from the result
    5275                 :   return ConvertToJS(cx, fninfo->mReturnType, NULL, returnValue.mData,
    5276               0 :                      false, true, vp);
    5277                 : }
    5278                 : 
    5279                 : FunctionInfo*
    5280               0 : FunctionType::GetFunctionInfo(JSObject* obj)
    5281                 : {
    5282               0 :   JS_ASSERT(CType::IsCType(obj));
    5283               0 :   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_function);
    5284                 : 
    5285               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_FNINFO);
    5286               0 :   JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot));
    5287                 : 
    5288               0 :   return static_cast<FunctionInfo*>(JSVAL_TO_PRIVATE(slot));
    5289                 : }
    5290                 : 
    5291                 : static JSBool
    5292               0 : CheckFunctionType(JSContext* cx, JSObject* obj)
    5293                 : {
    5294               0 :   if (!CType::IsCType(obj) || CType::GetTypeCode(obj) != TYPE_function) {
    5295               0 :     JS_ReportError(cx, "not a FunctionType");
    5296               0 :     return JS_FALSE;
    5297                 :   }
    5298               0 :   return JS_TRUE;
    5299                 : }
    5300                 : 
    5301                 : JSBool
    5302               0 : FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    5303                 : {
    5304               0 :   if (!CheckFunctionType(cx, obj))
    5305               0 :     return JS_FALSE;
    5306                 : 
    5307                 :   // Check if we have a cached argTypes array.
    5308               0 :   *vp = JS_GetReservedSlot(obj, SLOT_ARGS_T);
    5309               0 :   if (!JSVAL_IS_VOID(*vp))
    5310               0 :     return JS_TRUE;
    5311                 : 
    5312               0 :   FunctionInfo* fninfo = GetFunctionInfo(obj);
    5313               0 :   size_t len = fninfo->mArgTypes.length();
    5314                 : 
    5315                 :   // Prepare a new array.
    5316               0 :   Array<jsval, 16> vec;
    5317               0 :   if (!vec.resize(len))
    5318               0 :     return JS_FALSE;
    5319                 : 
    5320               0 :   for (size_t i = 0; i < len; ++i)
    5321               0 :     vec[i] = OBJECT_TO_JSVAL(fninfo->mArgTypes[i]);
    5322                 : 
    5323               0 :   JSObject* argTypes = JS_NewArrayObject(cx, len, vec.begin());
    5324               0 :   if (!argTypes)
    5325               0 :     return JS_FALSE;
    5326                 : 
    5327                 :   // Seal and cache it.
    5328               0 :   if (!JS_FreezeObject(cx, argTypes))
    5329               0 :     return JS_FALSE;
    5330               0 :   JS_SetReservedSlot(obj, SLOT_ARGS_T, OBJECT_TO_JSVAL(argTypes));
    5331                 : 
    5332               0 :   *vp = OBJECT_TO_JSVAL(argTypes);
    5333               0 :   return JS_TRUE;
    5334                 : }
    5335                 : 
    5336                 : JSBool
    5337               0 : FunctionType::ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    5338                 : {
    5339               0 :   if (!CheckFunctionType(cx, obj))
    5340               0 :     return JS_FALSE;
    5341                 : 
    5342                 :   // Get the returnType object from the FunctionInfo.
    5343               0 :   *vp = OBJECT_TO_JSVAL(GetFunctionInfo(obj)->mReturnType);
    5344               0 :   return JS_TRUE;
    5345                 : }
    5346                 : 
    5347                 : JSBool
    5348               0 : FunctionType::ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    5349                 : {
    5350               0 :   if (!CheckFunctionType(cx, obj))
    5351               0 :     return JS_FALSE;
    5352                 : 
    5353                 :   // Get the abi object from the FunctionInfo.
    5354               0 :   *vp = OBJECT_TO_JSVAL(GetFunctionInfo(obj)->mABI);
    5355               0 :   return JS_TRUE;
    5356                 : }
    5357                 : 
    5358                 : JSBool
    5359               0 : FunctionType::IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    5360                 : {
    5361               0 :   if (!CheckFunctionType(cx, obj))
    5362               0 :     return JS_FALSE;
    5363                 : 
    5364               0 :   *vp = BOOLEAN_TO_JSVAL(GetFunctionInfo(obj)->mIsVariadic);
    5365               0 :   return JS_TRUE;
    5366                 : }
    5367                 : 
    5368                 : /*******************************************************************************
    5369                 : ** CClosure implementation
    5370                 : *******************************************************************************/
    5371                 : 
    5372                 : JSObject*
    5373               0 : CClosure::Create(JSContext* cx,
    5374                 :                  JSObject* typeObj,
    5375                 :                  JSObject* fnObj,
    5376                 :                  JSObject* thisObj,
    5377                 :                  jsval errVal,
    5378                 :                  PRFuncPtr* fnptr)
    5379                 : {
    5380               0 :   JS_ASSERT(fnObj);
    5381                 : 
    5382               0 :   JSObject* result = JS_NewObject(cx, &sCClosureClass, NULL, NULL);
    5383               0 :   if (!result)
    5384               0 :     return NULL;
    5385               0 :   js::AutoObjectRooter root(cx, result);
    5386                 : 
    5387                 :   // Get the FunctionInfo from the FunctionType.
    5388               0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    5389               0 :   JS_ASSERT(!fninfo->mIsVariadic);
    5390               0 :   JS_ASSERT(GetABICode(fninfo->mABI) != ABI_WINAPI);
    5391                 : 
    5392               0 :   AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>(JS_GetRuntime(cx)));
    5393               0 :   if (!cinfo) {
    5394               0 :     JS_ReportOutOfMemory(cx);
    5395               0 :     return NULL;
    5396                 :   }
    5397                 : 
    5398                 :   // Get the prototype of the FunctionType object, of class CTypeProto,
    5399                 :   // which stores our JSContext for use with the closure.
    5400               0 :   JSObject* proto = JS_GetPrototype(typeObj);
    5401               0 :   JS_ASSERT(proto);
    5402               0 :   JS_ASSERT(CType::IsCTypeProto(proto));
    5403                 : 
    5404                 :   // Get a JSContext for use with the closure.
    5405               0 :   jsval slot = JS_GetReservedSlot(proto, SLOT_CLOSURECX);
    5406               0 :   if (!JSVAL_IS_VOID(slot)) {
    5407                 :     // Use the existing JSContext.
    5408               0 :     cinfo->cx = static_cast<JSContext*>(JSVAL_TO_PRIVATE(slot));
    5409               0 :     JS_ASSERT(cinfo->cx);
    5410                 :   } else {
    5411                 :     // Lazily instantiate a new JSContext, and stash it on
    5412                 :     // ctypes.FunctionType.prototype.
    5413               0 :     JSRuntime* runtime = JS_GetRuntime(cx);
    5414               0 :     cinfo->cx = JS_NewContext(runtime, 8192);
    5415               0 :     if (!cinfo->cx) {
    5416               0 :       JS_ReportOutOfMemory(cx);
    5417               0 :       return NULL;
    5418                 :     }
    5419                 : 
    5420               0 :     JS_SetReservedSlot(proto, SLOT_CLOSURECX, PRIVATE_TO_JSVAL(cinfo->cx));
    5421                 :   }
    5422                 : 
    5423                 :   // Prepare the error sentinel value. It's important to do this now, because
    5424                 :   // we might be unable to convert the value to the proper type. If so, we want
    5425                 :   // the caller to know about it _now_, rather than some uncertain time in the
    5426                 :   // future when the error sentinel is actually needed.
    5427               0 :   if (!JSVAL_IS_VOID(errVal)) {
    5428                 : 
    5429                 :     // Make sure the callback returns something.
    5430               0 :     if (CType::GetTypeCode(fninfo->mReturnType) == TYPE_void_t) {
    5431               0 :       JS_ReportError(cx, "A void callback can't pass an error sentinel");
    5432               0 :       return NULL;
    5433                 :     }
    5434                 : 
    5435                 :     // With the exception of void, the FunctionType constructor ensures that
    5436                 :     // the return type has a defined size.
    5437               0 :     JS_ASSERT(CType::IsSizeDefined(fninfo->mReturnType));
    5438                 : 
    5439                 :     // Allocate a buffer for the return value.
    5440               0 :     size_t rvSize = CType::GetSize(fninfo->mReturnType);
    5441               0 :     cinfo->errResult = cx->malloc_(rvSize);
    5442               0 :     if (!cinfo->errResult)
    5443               0 :       return NULL;
    5444                 : 
    5445                 :     // Do the value conversion. This might fail, in which case we throw.
    5446               0 :     if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, cinfo->errResult,
    5447               0 :                          false, NULL))
    5448               0 :       return NULL;
    5449                 :   } else {
    5450               0 :     cinfo->errResult = NULL;
    5451                 :   }
    5452                 : 
    5453                 :   // Copy the important bits of context into cinfo.
    5454               0 :   cinfo->closureObj = result;
    5455               0 :   cinfo->typeObj = typeObj;
    5456               0 :   cinfo->thisObj = thisObj;
    5457               0 :   cinfo->jsfnObj = fnObj;
    5458                 : 
    5459                 :   // Create an ffi_closure object and initialize it.
    5460                 :   void* code;
    5461               0 :   cinfo->closure =
    5462               0 :     static_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &code));
    5463               0 :   if (!cinfo->closure || !code) {
    5464               0 :     JS_ReportError(cx, "couldn't create closure - libffi error");
    5465               0 :     return NULL;
    5466                 :   }
    5467                 : 
    5468               0 :   ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF,
    5469               0 :     CClosure::ClosureStub, cinfo.get(), code);
    5470               0 :   if (status != FFI_OK) {
    5471               0 :     JS_ReportError(cx, "couldn't create closure - libffi error");
    5472               0 :     return NULL;
    5473                 :   }
    5474                 : 
    5475                 :   // Stash the ClosureInfo struct on our new object.
    5476               0 :   JS_SetReservedSlot(result, SLOT_CLOSUREINFO, PRIVATE_TO_JSVAL(cinfo.forget()));
    5477                 : 
    5478                 :   // Casting between void* and a function pointer is forbidden in C and C++.
    5479                 :   // Do it via an integral type.
    5480               0 :   *fnptr = reinterpret_cast<PRFuncPtr>(reinterpret_cast<uintptr_t>(code));
    5481               0 :   return result;
    5482                 : }
    5483                 : 
    5484                 : void
    5485               0 : CClosure::Trace(JSTracer* trc, JSObject* obj)
    5486                 : {
    5487                 :   // Make sure our ClosureInfo slot is legit. If it's not, bail.
    5488               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
    5489               0 :   if (JSVAL_IS_VOID(slot))
    5490               0 :     return;
    5491                 : 
    5492               0 :   ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
    5493                 : 
    5494                 :   // Identify our objects to the tracer. (There's no need to identify
    5495                 :   // 'closureObj', since that's us.)
    5496               0 :   JS_CALL_OBJECT_TRACER(trc, cinfo->typeObj, "typeObj");
    5497               0 :   JS_CALL_OBJECT_TRACER(trc, cinfo->jsfnObj, "jsfnObj");
    5498               0 :   if (cinfo->thisObj)
    5499               0 :     JS_CALL_OBJECT_TRACER(trc, cinfo->thisObj, "thisObj");
    5500                 : }
    5501                 : 
    5502                 : void
    5503               0 : CClosure::Finalize(JSFreeOp *fop, JSObject* obj)
    5504                 : {
    5505                 :   // Make sure our ClosureInfo slot is legit. If it's not, bail.
    5506               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_CLOSUREINFO);
    5507               0 :   if (JSVAL_IS_VOID(slot))
    5508               0 :     return;
    5509                 : 
    5510               0 :   ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
    5511               0 :   FreeOp::get(fop)->delete_(cinfo);
    5512                 : }
    5513                 : 
    5514                 : void
    5515               0 : CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
    5516                 : {
    5517               0 :   JS_ASSERT(cif);
    5518               0 :   JS_ASSERT(result);
    5519               0 :   JS_ASSERT(args);
    5520               0 :   JS_ASSERT(userData);
    5521                 : 
    5522                 :   // Retrieve the essentials from our closure object.
    5523               0 :   ClosureInfo* cinfo = static_cast<ClosureInfo*>(userData);
    5524               0 :   JSContext* cx = cinfo->cx;
    5525               0 :   JSObject* typeObj = cinfo->typeObj;
    5526               0 :   JSObject* thisObj = cinfo->thisObj;
    5527               0 :   JSObject* jsfnObj = cinfo->jsfnObj;
    5528                 : 
    5529               0 :   JS_AbortIfWrongThread(JS_GetRuntime(cx));
    5530                 : 
    5531               0 :   JSAutoRequest ar(cx);
    5532                 : 
    5533               0 :   JSAutoEnterCompartment ac;
    5534               0 :   if (!ac.enter(cx, jsfnObj))
    5535                 :     return;
    5536                 : 
    5537                 :   // Assert that our CIFs agree.
    5538               0 :   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
    5539               0 :   JS_ASSERT(cif == &fninfo->mCIF);
    5540                 : 
    5541               0 :   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
    5542                 : 
    5543                 :   // Initialize the result to zero, in case something fails. Small integer types
    5544                 :   // are promoted to a word-sized ffi_arg, so we must be careful to zero the
    5545                 :   // whole word.
    5546               0 :   size_t rvSize = 0;
    5547               0 :   if (cif->rtype != &ffi_type_void) {
    5548               0 :     rvSize = cif->rtype->size;
    5549               0 :     switch (typeCode) {
    5550                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    5551                 :     case TYPE_##name:
    5552                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5553                 : #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5554                 : #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5555                 : #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5556                 : #include "typedefs.h"
    5557               0 :       rvSize = Align(rvSize, sizeof(ffi_arg));
    5558               0 :       break;
    5559                 :     default:
    5560               0 :       break;
    5561                 :     }
    5562               0 :     memset(result, 0, rvSize);
    5563                 :   }
    5564                 : 
    5565                 :   // Get a death grip on 'closureObj'.
    5566               0 :   js::AutoObjectRooter root(cx, cinfo->closureObj);
    5567                 : 
    5568                 :   // Set up an array for converted arguments.
    5569               0 :   Array<jsval, 16> argv;
    5570               0 :   if (!argv.appendN(JSVAL_VOID, cif->nargs)) {
    5571               0 :     JS_ReportOutOfMemory(cx);
    5572                 :     return;
    5573                 :   }
    5574                 : 
    5575               0 :   js::AutoArrayRooter roots(cx, argv.length(), argv.begin());
    5576               0 :   for (uint32_t i = 0; i < cif->nargs; ++i) {
    5577                 :     // Convert each argument, and have any CData objects created depend on
    5578                 :     // the existing buffers.
    5579               0 :     if (!ConvertToJS(cx, fninfo->mArgTypes[i], NULL, args[i], false, false,
    5580               0 :            &argv[i]))
    5581                 :       return;
    5582                 :   }
    5583                 : 
    5584                 :   // Call the JS function. 'thisObj' may be NULL, in which case the JS engine
    5585                 :   // will find an appropriate object to use.
    5586                 :   jsval rval;
    5587                 :   JSBool success = JS_CallFunctionValue(cx, thisObj, OBJECT_TO_JSVAL(jsfnObj),
    5588               0 :                                         cif->nargs, argv.begin(), &rval);
    5589                 : 
    5590                 :   // Convert the result. Note that we pass 'isArgument = false', such that
    5591                 :   // ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char
    5592                 :   // type, which would require an allocation that we can't track. The JS
    5593                 :   // function must perform this conversion itself and return a PointerType
    5594                 :   // CData; thusly, the burden of freeing the data is left to the user.
    5595               0 :   if (success && cif->rtype != &ffi_type_void)
    5596                 :     success = ImplicitConvert(cx, rval, fninfo->mReturnType, result, false,
    5597               0 :                               NULL);
    5598                 : 
    5599               0 :   if (!success) {
    5600                 :     // Something failed. The callee may have thrown, or it may not have
    5601                 :     // returned a value that ImplicitConvert() was happy with. Depending on how
    5602                 :     // prudent the consumer has been, we may or may not have a recovery plan.
    5603                 : 
    5604                 :     // In any case, a JS exception cannot be passed to C code, so report the
    5605                 :     // exception if any and clear it from the cx.
    5606               0 :     if (JS_IsExceptionPending(cx))
    5607               0 :       JS_ReportPendingException(cx);
    5608                 : 
    5609               0 :     if (cinfo->errResult) {
    5610                 :       // Good case: we have a sentinel that we can return. Copy it in place of
    5611                 :       // the actual return value, and then proceed.
    5612                 : 
    5613                 :       // The buffer we're returning might be larger than the size of the return
    5614                 :       // type, due to libffi alignment issues (see above). But it should never
    5615                 :       // be smaller.
    5616               0 :       size_t copySize = CType::GetSize(fninfo->mReturnType);
    5617               0 :       JS_ASSERT(copySize <= rvSize);
    5618               0 :       memcpy(result, cinfo->errResult, copySize);
    5619                 :     } else {
    5620                 :       // Bad case: not much we can do here. The rv is already zeroed out, so we
    5621                 :       // just report (another) error and hope for the best. JS_ReportError will
    5622                 :       // actually throw an exception here, so then we have to report it. Again.
    5623                 :       // Ugh.
    5624                 :       JS_ReportError(cx, "JavaScript callback failed, and an error sentinel "
    5625               0 :                          "was not specified.");
    5626               0 :       if (JS_IsExceptionPending(cx))
    5627               0 :         JS_ReportPendingException(cx);
    5628                 : 
    5629                 :       return;
    5630                 :     }
    5631                 :   }
    5632                 : 
    5633                 :   // Small integer types must be returned as a word-sized ffi_arg. Coerce it
    5634                 :   // back into the size libffi expects.
    5635               0 :   switch (typeCode) {
    5636                 : #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
    5637                 :   case TYPE_##name:                                                            \
    5638                 :     if (sizeof(type) < sizeof(ffi_arg)) {                                      \
    5639                 :       ffi_arg data = *static_cast<type*>(result);                              \
    5640                 :       *static_cast<ffi_arg*>(result) = data;                                   \
    5641                 :     }                                                                          \
    5642                 :     break;
    5643                 : #define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5644                 : #define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5645                 : #define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5646                 : #define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
    5647                 : #include "typedefs.h"
    5648                 :   default:
    5649               0 :     break;
    5650                 :   }
    5651                 : }
    5652                 : 
    5653                 : /*******************************************************************************
    5654                 : ** CData implementation
    5655                 : *******************************************************************************/
    5656                 : 
    5657                 : // Create a new CData object of type 'typeObj' containing binary data supplied
    5658                 : // in 'source', optionally with a referent object 'refObj'.
    5659                 : //
    5660                 : // * 'typeObj' must be a CType of defined (but possibly zero) size.
    5661                 : //
    5662                 : // * If an object 'refObj' is supplied, the new CData object stores the
    5663                 : //   referent object in a reserved slot for GC safety, such that 'refObj' will
    5664                 : //   be held alive by the resulting CData object. 'refObj' may or may not be
    5665                 : //   a CData object; merely an object we want to keep alive.
    5666                 : //   * If 'refObj' is a CData object, 'ownResult' must be false.
    5667                 : //   * Otherwise, 'refObj' is a Library or CClosure object, and 'ownResult'
    5668                 : //     may be true or false.
    5669                 : // * Otherwise 'refObj' is NULL. In this case, 'ownResult' may be true or false.
    5670                 : //
    5671                 : // * If 'ownResult' is true, the CData object will allocate an appropriately
    5672                 : //   sized buffer, and free it upon finalization. If 'source' data is
    5673                 : //   supplied, the data will be copied from 'source' into the buffer;
    5674                 : //   otherwise, the entirety of the new buffer will be initialized to zero.
    5675                 : // * If 'ownResult' is false, the new CData's buffer refers to a slice of
    5676                 : //   another buffer kept alive by 'refObj'. 'source' data must be provided,
    5677                 : //   and the new CData's buffer will refer to 'source'.
    5678                 : JSObject*
    5679               0 : CData::Create(JSContext* cx,
    5680                 :               JSObject* typeObj,
    5681                 :               JSObject* refObj,
    5682                 :               void* source,
    5683                 :               bool ownResult)
    5684                 : {
    5685               0 :   JS_ASSERT(typeObj);
    5686               0 :   JS_ASSERT(CType::IsCType(typeObj));
    5687               0 :   JS_ASSERT(CType::IsSizeDefined(typeObj));
    5688               0 :   JS_ASSERT(ownResult || source);
    5689               0 :   JS_ASSERT_IF(refObj && CData::IsCData(refObj), !ownResult);
    5690                 : 
    5691                 :   // Get the 'prototype' property from the type.
    5692               0 :   jsval slot = JS_GetReservedSlot(typeObj, SLOT_PROTO);
    5693               0 :   JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot));
    5694                 : 
    5695               0 :   JSObject* proto = JSVAL_TO_OBJECT(slot);
    5696               0 :   JSObject* parent = JS_GetParent(typeObj);
    5697               0 :   JS_ASSERT(parent);
    5698                 : 
    5699               0 :   JSObject* dataObj = JS_NewObject(cx, &sCDataClass, proto, parent);
    5700               0 :   if (!dataObj)
    5701               0 :     return NULL;
    5702               0 :   js::AutoObjectRooter root(cx, dataObj);
    5703                 : 
    5704                 :   // set the CData's associated type
    5705               0 :   JS_SetReservedSlot(dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj));
    5706                 : 
    5707                 :   // Stash the referent object, if any, for GC safety.
    5708               0 :   if (refObj)
    5709               0 :     JS_SetReservedSlot(dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(refObj));
    5710                 : 
    5711                 :   // Set our ownership flag.
    5712               0 :   JS_SetReservedSlot(dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult));
    5713                 : 
    5714                 :   // attach the buffer. since it might not be 2-byte aligned, we need to
    5715                 :   // allocate an aligned space for it and store it there. :(
    5716               0 :   char** buffer = cx->new_<char*>();
    5717               0 :   if (!buffer) {
    5718               0 :     JS_ReportOutOfMemory(cx);
    5719               0 :     return NULL;
    5720                 :   }
    5721                 : 
    5722                 :   char* data;
    5723               0 :   if (!ownResult) {
    5724               0 :     data = static_cast<char*>(source);
    5725                 :   } else {
    5726                 :     // Initialize our own buffer.
    5727               0 :     size_t size = CType::GetSize(typeObj);
    5728               0 :     data = cx->array_new<char>(size);
    5729               0 :     if (!data) {
    5730                 :       // Report a catchable allocation error.
    5731               0 :       JS_ReportAllocationOverflow(cx);
    5732               0 :       Foreground::delete_(buffer);
    5733               0 :       return NULL;
    5734                 :     }
    5735                 : 
    5736               0 :     if (!source)
    5737               0 :       memset(data, 0, size);
    5738                 :     else
    5739               0 :       memcpy(data, source, size);
    5740                 :   }
    5741                 : 
    5742               0 :   *buffer = data;
    5743               0 :   JS_SetReservedSlot(dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer));
    5744                 : 
    5745               0 :   return dataObj;
    5746                 : }
    5747                 : 
    5748                 : void
    5749               0 : CData::Finalize(JSFreeOp *fop, JSObject* obj)
    5750                 : {
    5751                 :   // Delete our buffer, and the data it contains if we own it.
    5752               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_OWNS);
    5753               0 :   if (JSVAL_IS_VOID(slot))
    5754               0 :     return;
    5755                 : 
    5756               0 :   JSBool owns = JSVAL_TO_BOOLEAN(slot);
    5757                 : 
    5758               0 :   slot = JS_GetReservedSlot(obj, SLOT_DATA);
    5759               0 :   if (JSVAL_IS_VOID(slot))
    5760               0 :     return;
    5761               0 :   char** buffer = static_cast<char**>(JSVAL_TO_PRIVATE(slot));
    5762                 : 
    5763               0 :   if (owns)
    5764               0 :     FreeOp::get(fop)->array_delete(*buffer);
    5765               0 :   FreeOp::get(fop)->delete_(buffer);
    5766                 : }
    5767                 : 
    5768                 : JSObject*
    5769               0 : CData::GetCType(JSObject* dataObj)
    5770                 : {
    5771               0 :   JS_ASSERT(CData::IsCData(dataObj));
    5772                 : 
    5773               0 :   jsval slot = JS_GetReservedSlot(dataObj, SLOT_CTYPE);
    5774               0 :   JSObject* typeObj = JSVAL_TO_OBJECT(slot);
    5775               0 :   JS_ASSERT(CType::IsCType(typeObj));
    5776               0 :   return typeObj;
    5777                 : }
    5778                 : 
    5779                 : void*
    5780               0 : CData::GetData(JSObject* dataObj)
    5781                 : {
    5782               0 :   JS_ASSERT(CData::IsCData(dataObj));
    5783                 : 
    5784               0 :   jsval slot = JS_GetReservedSlot(dataObj, SLOT_DATA);
    5785                 : 
    5786               0 :   void** buffer = static_cast<void**>(JSVAL_TO_PRIVATE(slot));
    5787               0 :   JS_ASSERT(buffer);
    5788               0 :   JS_ASSERT(*buffer);
    5789               0 :   return *buffer;
    5790                 : }
    5791                 : 
    5792                 : bool
    5793               0 : CData::IsCData(JSObject* obj)
    5794                 : {
    5795               0 :   return JS_GetClass(obj) == &sCDataClass;
    5796                 : }
    5797                 : 
    5798                 : bool
    5799               0 : CData::IsCDataProto(JSObject* obj)
    5800                 : {
    5801               0 :   return JS_GetClass(obj) == &sCDataProtoClass;
    5802                 : }
    5803                 : 
    5804                 : JSBool
    5805               0 : CData::ValueGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
    5806                 : {
    5807               0 :   if (!IsCData(obj)) {
    5808               0 :     JS_ReportError(cx, "not a CData");
    5809               0 :     return JS_FALSE;
    5810                 :   }
    5811                 : 
    5812                 :   // Convert the value to a primitive; do not create a new CData object.
    5813               0 :   if (!ConvertToJS(cx, GetCType(obj), NULL, GetData(obj), true, false, vp))
    5814               0 :     return JS_FALSE;
    5815                 : 
    5816               0 :   return JS_TRUE;
    5817                 : }
    5818                 : 
    5819                 : JSBool
    5820               0 : CData::ValueSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp)
    5821                 : {
    5822               0 :   if (!IsCData(obj)) {
    5823               0 :     JS_ReportError(cx, "not a CData");
    5824               0 :     return JS_FALSE;
    5825                 :   }
    5826                 : 
    5827               0 :   return ImplicitConvert(cx, *vp, GetCType(obj), GetData(obj), false, NULL);
    5828                 : }
    5829                 : 
    5830                 : JSBool
    5831               0 : CData::Address(JSContext* cx, unsigned argc, jsval* vp)
    5832                 : {
    5833               0 :   if (argc != 0) {
    5834               0 :     JS_ReportError(cx, "address takes zero arguments");
    5835               0 :     return JS_FALSE;
    5836                 :   }
    5837                 : 
    5838               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    5839               0 :   if (!obj || !IsCData(obj)) {
    5840               0 :     JS_ReportError(cx, "not a CData");
    5841               0 :     return JS_FALSE;
    5842                 :   }
    5843                 : 
    5844               0 :   JSObject* typeObj = CData::GetCType(obj);
    5845               0 :   JSObject* pointerType = PointerType::CreateInternal(cx, typeObj);
    5846               0 :   if (!pointerType)
    5847               0 :     return JS_FALSE;
    5848               0 :   js::AutoObjectRooter root(cx, pointerType);
    5849                 : 
    5850                 :   // Create a PointerType CData object containing null.
    5851               0 :   JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true);
    5852               0 :   if (!result)
    5853               0 :     return JS_FALSE;
    5854                 : 
    5855               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    5856                 : 
    5857                 :   // Manually set the pointer inside the object, so we skip the conversion step.
    5858               0 :   void** data = static_cast<void**>(GetData(result));
    5859               0 :   *data = GetData(obj);
    5860               0 :   return JS_TRUE;
    5861                 : }
    5862                 : 
    5863                 : JSBool
    5864               0 : CData::Cast(JSContext* cx, unsigned argc, jsval* vp)
    5865                 : {
    5866               0 :   if (argc != 2) {
    5867               0 :     JS_ReportError(cx, "cast takes two arguments");
    5868               0 :     return JS_FALSE;
    5869                 :   }
    5870                 : 
    5871               0 :   jsval* argv = JS_ARGV(cx, vp);
    5872               0 :   if (JSVAL_IS_PRIMITIVE(argv[0]) ||
    5873               0 :       !CData::IsCData(JSVAL_TO_OBJECT(argv[0]))) {
    5874               0 :     JS_ReportError(cx, "first argument must be a CData");
    5875               0 :     return JS_FALSE;
    5876                 :   }
    5877               0 :   JSObject* sourceData = JSVAL_TO_OBJECT(argv[0]);
    5878               0 :   JSObject* sourceType = CData::GetCType(sourceData);
    5879                 : 
    5880               0 :   if (JSVAL_IS_PRIMITIVE(argv[1]) ||
    5881               0 :       !CType::IsCType(JSVAL_TO_OBJECT(argv[1]))) {
    5882               0 :     JS_ReportError(cx, "second argument must be a CType");
    5883               0 :     return JS_FALSE;
    5884                 :   }
    5885                 : 
    5886               0 :   JSObject* targetType = JSVAL_TO_OBJECT(argv[1]);
    5887                 :   size_t targetSize;
    5888               0 :   if (!CType::GetSafeSize(targetType, &targetSize) ||
    5889               0 :       targetSize > CType::GetSize(sourceType)) {
    5890                 :     JS_ReportError(cx,
    5891               0 :       "target CType has undefined or larger size than source CType");
    5892               0 :     return JS_FALSE;
    5893                 :   }
    5894                 : 
    5895                 :   // Construct a new CData object with a type of 'targetType' and a referent
    5896                 :   // of 'sourceData'.
    5897               0 :   void* data = CData::GetData(sourceData);
    5898               0 :   JSObject* result = CData::Create(cx, targetType, sourceData, data, false);
    5899               0 :   if (!result)
    5900               0 :     return JS_FALSE;
    5901                 : 
    5902               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    5903               0 :   return JS_TRUE;
    5904                 : }
    5905                 : 
    5906                 : JSBool
    5907               0 : CData::GetRuntime(JSContext* cx, unsigned argc, jsval* vp)
    5908                 : {
    5909               0 :   if (argc != 1) {
    5910               0 :     JS_ReportError(cx, "getRuntime takes one argument");
    5911               0 :     return JS_FALSE;
    5912                 :   }
    5913                 : 
    5914               0 :   jsval* argv = JS_ARGV(cx, vp);
    5915               0 :   if (JSVAL_IS_PRIMITIVE(argv[0]) ||
    5916               0 :       !CType::IsCType(JSVAL_TO_OBJECT(argv[0]))) {
    5917               0 :     JS_ReportError(cx, "first argument must be a CType");
    5918               0 :     return JS_FALSE;
    5919                 :   }
    5920                 : 
    5921               0 :   JSObject* targetType = JSVAL_TO_OBJECT(argv[0]);
    5922                 :   size_t targetSize;
    5923               0 :   if (!CType::GetSafeSize(targetType, &targetSize) ||
    5924                 :       targetSize != sizeof(void*)) {
    5925               0 :     JS_ReportError(cx, "target CType has non-pointer size");
    5926               0 :     return JS_FALSE;
    5927                 :   }
    5928                 : 
    5929               0 :   void* data = static_cast<void*>(cx->runtime);
    5930               0 :   JSObject* result = CData::Create(cx, targetType, NULL, &data, true);
    5931               0 :   if (!result)
    5932               0 :     return JS_FALSE;
    5933                 : 
    5934               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    5935               0 :   return JS_TRUE;
    5936                 : }
    5937                 : 
    5938                 : JSBool
    5939               0 : CData::ReadString(JSContext* cx, unsigned argc, jsval* vp)
    5940                 : {
    5941               0 :   if (argc != 0) {
    5942               0 :     JS_ReportError(cx, "readString takes zero arguments");
    5943               0 :     return JS_FALSE;
    5944                 :   }
    5945                 : 
    5946               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    5947               0 :   if (!obj || !IsCData(obj)) {
    5948               0 :     JS_ReportError(cx, "not a CData");
    5949               0 :     return JS_FALSE;
    5950                 :   }
    5951                 : 
    5952                 :   // Make sure we are a pointer to, or an array of, an 8-bit or 16-bit
    5953                 :   // character or integer type.
    5954                 :   JSObject* baseType;
    5955               0 :   JSObject* typeObj = GetCType(obj);
    5956               0 :   TypeCode typeCode = CType::GetTypeCode(typeObj);
    5957                 :   void* data;
    5958               0 :   size_t maxLength = -1;
    5959               0 :   switch (typeCode) {
    5960                 :   case TYPE_pointer:
    5961               0 :     baseType = PointerType::GetBaseType(typeObj);
    5962               0 :     data = *static_cast<void**>(GetData(obj));
    5963               0 :     if (data == NULL) {
    5964               0 :       JS_ReportError(cx, "cannot read contents of null pointer");
    5965               0 :       return JS_FALSE;
    5966                 :     }
    5967               0 :     break;
    5968                 :   case TYPE_array:
    5969               0 :     baseType = ArrayType::GetBaseType(typeObj);
    5970               0 :     data = GetData(obj);
    5971               0 :     maxLength = ArrayType::GetLength(typeObj);
    5972               0 :     break;
    5973                 :   default:
    5974               0 :     JS_ReportError(cx, "not a PointerType or ArrayType");
    5975               0 :     return JS_FALSE;
    5976                 :   }
    5977                 : 
    5978                 :   // Convert the string buffer, taking care to determine the correct string
    5979                 :   // length in the case of arrays (which may contain embedded nulls).
    5980                 :   JSString* result;
    5981               0 :   switch (CType::GetTypeCode(baseType)) {
    5982                 :   case TYPE_int8_t:
    5983                 :   case TYPE_uint8_t:
    5984                 :   case TYPE_char:
    5985                 :   case TYPE_signed_char:
    5986                 :   case TYPE_unsigned_char: {
    5987               0 :     char* bytes = static_cast<char*>(data);
    5988               0 :     size_t length = strnlen(bytes, maxLength);
    5989                 : 
    5990                 :     // Determine the length.
    5991                 :     size_t dstlen;
    5992               0 :     if (!InflateUTF8StringToBuffer(cx, bytes, length, NULL, &dstlen))
    5993               0 :       return JS_FALSE;
    5994                 : 
    5995                 :     jschar* dst =
    5996               0 :       static_cast<jschar*>(JS_malloc(cx, (dstlen + 1) * sizeof(jschar)));
    5997               0 :     if (!dst)
    5998               0 :       return JS_FALSE;
    5999                 : 
    6000               0 :     ASSERT_OK(InflateUTF8StringToBuffer(cx, bytes, length, dst, &dstlen));
    6001               0 :     dst[dstlen] = 0;
    6002                 : 
    6003               0 :     result = JS_NewUCString(cx, dst, dstlen);
    6004               0 :     break;
    6005                 :   }
    6006                 :   case TYPE_int16_t:
    6007                 :   case TYPE_uint16_t:
    6008                 :   case TYPE_short:
    6009                 :   case TYPE_unsigned_short:
    6010                 :   case TYPE_jschar: {
    6011               0 :     jschar* chars = static_cast<jschar*>(data);
    6012               0 :     size_t length = strnlen(chars, maxLength);
    6013               0 :     result = JS_NewUCStringCopyN(cx, chars, length);
    6014               0 :     break;
    6015                 :   }
    6016                 :   default:
    6017                 :     JS_ReportError(cx,
    6018               0 :       "base type is not an 8-bit or 16-bit integer or character type");
    6019               0 :     return JS_FALSE;
    6020                 :   }
    6021                 : 
    6022               0 :   if (!result)
    6023               0 :     return JS_FALSE;
    6024                 : 
    6025               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    6026               0 :   return JS_TRUE;
    6027                 : }
    6028                 : 
    6029                 : JSBool
    6030               0 : CData::ToSource(JSContext* cx, unsigned argc, jsval* vp)
    6031                 : {
    6032               0 :   if (argc != 0) {
    6033               0 :     JS_ReportError(cx, "toSource takes zero arguments");
    6034               0 :     return JS_FALSE;
    6035                 :   }
    6036                 : 
    6037               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    6038               0 :   if (!obj ||
    6039               0 :       !(CData::IsCData(obj) || CData::IsCDataProto(obj))) {
    6040               0 :     JS_ReportError(cx, "not a CData");
    6041               0 :     return JS_FALSE;
    6042                 :   }
    6043                 : 
    6044                 :   JSString* result;
    6045               0 :   if (CData::IsCData(obj)) {
    6046               0 :     JSObject* typeObj = CData::GetCType(obj);
    6047               0 :     void* data = CData::GetData(obj);
    6048                 : 
    6049                 :     // Walk the types, building up the toSource() string.
    6050                 :     // First, we build up the type expression:
    6051                 :     // 't.ptr' for pointers;
    6052                 :     // 't.array([n])' for arrays;
    6053                 :     // 'n' for structs, where n = t.name, the struct's name. (We assume this is
    6054                 :     // bound to a variable in the current scope.)
    6055               0 :     AutoString source;
    6056               0 :     BuildTypeSource(cx, typeObj, true, source);
    6057               0 :     AppendString(source, "(");
    6058               0 :     if (!BuildDataSource(cx, typeObj, data, false, source))
    6059               0 :       return JS_FALSE;
    6060                 : 
    6061               0 :     AppendString(source, ")");
    6062                 : 
    6063               0 :     result = NewUCString(cx, source);
    6064                 :   }
    6065                 :   else
    6066               0 :     result = JS_NewStringCopyZ(cx, "[CData proto object]");
    6067               0 :   if (!result)
    6068               0 :     return JS_FALSE;
    6069                 : 
    6070               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    6071               0 :   return JS_TRUE;
    6072                 : }
    6073                 : 
    6074                 : JSBool
    6075               0 : CData::ErrnoGetter(JSContext* cx, JSObject* obj, jsid, jsval* vp)
    6076                 : {
    6077               0 :   if (!IsCTypesGlobal(obj)) {
    6078               0 :     JS_ReportError(cx, "this is not not global object ctypes");
    6079               0 :     return JS_FALSE;
    6080                 :   }
    6081                 : 
    6082               0 :   *vp = JS_GetReservedSlot(obj, SLOT_ERRNO);
    6083               0 :   return JS_TRUE;
    6084                 : }
    6085                 : 
    6086                 : #if defined(XP_WIN)
    6087                 : JSBool
    6088                 : CData::LastErrorGetter(JSContext* cx, JSObject* obj, jsid, jsval* vp)
    6089                 : {
    6090                 :   if (!IsCTypesGlobal(obj)) {
    6091                 :     JS_ReportError(cx, "not global object ctypes");
    6092                 :     return JS_FALSE;
    6093                 :   }
    6094                 : 
    6095                 : 
    6096                 :   *vp = JS_GetReservedSlot(obj, SLOT_LASTERROR);
    6097                 :   return JS_TRUE;
    6098                 : }
    6099                 : #endif // defined(XP_WIN)
    6100                 : 
    6101                 : /*******************************************************************************
    6102                 : ** Int64 and UInt64 implementation
    6103                 : *******************************************************************************/
    6104                 : 
    6105                 : JSObject*
    6106               0 : Int64Base::Construct(JSContext* cx,
    6107                 :                      JSObject* proto,
    6108                 :                      uint64_t data,
    6109                 :                      bool isUnsigned)
    6110                 : {
    6111               0 :   JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
    6112               0 :   JSObject* result = JS_NewObject(cx, clasp, proto, JS_GetParent(proto));
    6113               0 :   if (!result)
    6114               0 :     return NULL;
    6115               0 :   js::AutoObjectRooter root(cx, result);
    6116                 : 
    6117                 :   // attach the Int64's data
    6118               0 :   uint64_t* buffer = cx->new_<uint64_t>(data);
    6119               0 :   if (!buffer) {
    6120               0 :     JS_ReportOutOfMemory(cx);
    6121               0 :     return NULL;
    6122                 :   }
    6123                 : 
    6124               0 :   JS_SetReservedSlot(result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer));
    6125                 : 
    6126               0 :   if (!JS_FreezeObject(cx, result))
    6127               0 :     return NULL;
    6128                 : 
    6129               0 :   return result;
    6130                 : }
    6131                 : 
    6132                 : void
    6133               0 : Int64Base::Finalize(JSFreeOp *fop, JSObject* obj)
    6134                 : {
    6135               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
    6136               0 :   if (JSVAL_IS_VOID(slot))
    6137               0 :     return;
    6138                 : 
    6139               0 :   FreeOp::get(fop)->delete_(static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot)));
    6140                 : }
    6141                 : 
    6142                 : uint64_t
    6143               0 : Int64Base::GetInt(JSObject* obj) {
    6144               0 :   JS_ASSERT(Int64::IsInt64(obj) || UInt64::IsUInt64(obj));
    6145                 : 
    6146               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_INT64);
    6147               0 :   return *static_cast<uint64_t*>(JSVAL_TO_PRIVATE(slot));
    6148                 : }
    6149                 : 
    6150                 : JSBool
    6151               0 : Int64Base::ToString(JSContext* cx,
    6152                 :                     JSObject* obj,
    6153                 :                     unsigned argc,
    6154                 :                     jsval* vp,
    6155                 :                     bool isUnsigned)
    6156                 : {
    6157               0 :   if (argc > 1) {
    6158               0 :     JS_ReportError(cx, "toString takes zero or one argument");
    6159               0 :     return JS_FALSE;
    6160                 :   }
    6161                 : 
    6162               0 :   int radix = 10;
    6163               0 :   if (argc == 1) {
    6164               0 :     jsval arg = JS_ARGV(cx, vp)[0];
    6165               0 :     if (JSVAL_IS_INT(arg))
    6166               0 :       radix = JSVAL_TO_INT(arg);
    6167               0 :     if (!JSVAL_IS_INT(arg) || radix < 2 || radix > 36) {
    6168               0 :       JS_ReportError(cx, "radix argument must be an integer between 2 and 36");
    6169               0 :       return JS_FALSE;
    6170                 :     }
    6171                 :   }
    6172                 : 
    6173               0 :   AutoString intString;
    6174               0 :   if (isUnsigned) {
    6175               0 :     IntegerToString(GetInt(obj), radix, intString);
    6176                 :   } else {
    6177               0 :     IntegerToString(static_cast<int64_t>(GetInt(obj)), radix, intString);
    6178                 :   }
    6179                 : 
    6180               0 :   JSString *result = NewUCString(cx, intString);
    6181               0 :   if (!result)
    6182               0 :     return JS_FALSE;
    6183                 : 
    6184               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    6185               0 :   return JS_TRUE;
    6186                 : }
    6187                 : 
    6188                 : JSBool
    6189               0 : Int64Base::ToSource(JSContext* cx,
    6190                 :                     JSObject* obj,
    6191                 :                     unsigned argc,
    6192                 :                     jsval* vp,
    6193                 :                     bool isUnsigned)
    6194                 : {
    6195               0 :   if (argc != 0) {
    6196               0 :     JS_ReportError(cx, "toSource takes zero arguments");
    6197               0 :     return JS_FALSE;
    6198                 :   }
    6199                 : 
    6200                 :   // Return a decimal string suitable for constructing the number.
    6201               0 :   AutoString source;
    6202               0 :   if (isUnsigned) {
    6203               0 :     AppendString(source, "ctypes.UInt64(\"");
    6204               0 :     IntegerToString(GetInt(obj), 10, source);
    6205                 :   } else {
    6206               0 :     AppendString(source, "ctypes.Int64(\"");
    6207               0 :     IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
    6208                 :   }
    6209               0 :   AppendString(source, "\")");
    6210                 : 
    6211               0 :   JSString *result = NewUCString(cx, source);
    6212               0 :   if (!result)
    6213               0 :     return JS_FALSE;
    6214                 : 
    6215               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
    6216               0 :   return JS_TRUE;
    6217                 : }
    6218                 : 
    6219                 : JSBool
    6220               0 : Int64::Construct(JSContext* cx,
    6221                 :                  unsigned argc,
    6222                 :                  jsval* vp)
    6223                 : {
    6224                 :   // Construct and return a new Int64 object.
    6225               0 :   if (argc != 1) {
    6226               0 :     JS_ReportError(cx, "Int64 takes one argument");
    6227               0 :     return JS_FALSE;
    6228                 :   }
    6229                 : 
    6230               0 :   jsval* argv = JS_ARGV(cx, vp);
    6231               0 :   int64_t i = 0;
    6232               0 :   if (!jsvalToBigInteger(cx, argv[0], true, &i))
    6233               0 :     return TypeError(cx, "int64", argv[0]);
    6234                 : 
    6235                 :   // Get ctypes.Int64.prototype from the 'prototype' property of the ctor.
    6236                 :   jsval slot;
    6237                 :   ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)),
    6238               0 :     "prototype", &slot));
    6239               0 :   JSObject* proto = JSVAL_TO_OBJECT(slot);
    6240               0 :   JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
    6241                 : 
    6242               0 :   JSObject* result = Int64Base::Construct(cx, proto, i, false);
    6243               0 :   if (!result)
    6244               0 :     return JS_FALSE;
    6245                 : 
    6246               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    6247               0 :   return JS_TRUE;
    6248                 : }
    6249                 : 
    6250                 : bool
    6251               0 : Int64::IsInt64(JSObject* obj)
    6252                 : {
    6253               0 :   return JS_GetClass(obj) == &sInt64Class;
    6254                 : }
    6255                 : 
    6256                 : JSBool
    6257               0 : Int64::ToString(JSContext* cx, unsigned argc, jsval* vp)
    6258                 : {
    6259               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    6260               0 :   if (!obj || !Int64::IsInt64(obj)) {
    6261               0 :     JS_ReportError(cx, "not an Int64");
    6262               0 :     return JS_FALSE;
    6263                 :   }
    6264                 : 
    6265               0 :   return Int64Base::ToString(cx, obj, argc, vp, false);
    6266                 : }
    6267                 : 
    6268                 : JSBool
    6269               0 : Int64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
    6270                 : {
    6271               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    6272               0 :   if (!obj || !Int64::IsInt64(obj)) {
    6273               0 :     JS_ReportError(cx, "not an Int64");
    6274               0 :     return JS_FALSE;
    6275                 :   }
    6276                 : 
    6277               0 :   return Int64Base::ToSource(cx, obj, argc, vp, false);
    6278                 : }
    6279                 : 
    6280                 : JSBool
    6281               0 : Int64::Compare(JSContext* cx, unsigned argc, jsval* vp)
    6282                 : {
    6283               0 :   jsval* argv = JS_ARGV(cx, vp);
    6284               0 :   if (argc != 2 ||
    6285               0 :       JSVAL_IS_PRIMITIVE(argv[0]) ||
    6286               0 :       JSVAL_IS_PRIMITIVE(argv[1]) ||
    6287               0 :       !Int64::IsInt64(JSVAL_TO_OBJECT(argv[0])) ||
    6288               0 :       !Int64::IsInt64(JSVAL_TO_OBJECT(argv[1]))) {
    6289               0 :     JS_ReportError(cx, "compare takes two Int64 arguments");
    6290               0 :     return JS_FALSE;
    6291                 :   }
    6292                 : 
    6293               0 :   JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]);
    6294               0 :   JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]);
    6295                 : 
    6296               0 :   int64_t i1 = Int64Base::GetInt(obj1);
    6297               0 :   int64_t i2 = Int64Base::GetInt(obj2);
    6298                 : 
    6299               0 :   if (i1 == i2)
    6300               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0));
    6301               0 :   else if (i1 < i2)
    6302               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(-1));
    6303                 :   else
    6304               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(1));
    6305                 : 
    6306               0 :   return JS_TRUE;
    6307                 : }
    6308                 : 
    6309                 : #define LO_MASK ((uint64_t(1) << 32) - 1)
    6310                 : #define INT64_LO(i) ((i) & LO_MASK)
    6311                 : #define INT64_HI(i) ((i) >> 32)
    6312                 : 
    6313                 : JSBool
    6314               0 : Int64::Lo(JSContext* cx, unsigned argc, jsval* vp)
    6315                 : {
    6316               0 :   jsval* argv = JS_ARGV(cx, vp);
    6317               0 :   if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) ||
    6318               0 :       !Int64::IsInt64(JSVAL_TO_OBJECT(argv[0]))) {
    6319               0 :     JS_ReportError(cx, "lo takes one Int64 argument");
    6320               0 :     return JS_FALSE;
    6321                 :   }
    6322                 : 
    6323               0 :   JSObject* obj = JSVAL_TO_OBJECT(argv[0]);
    6324               0 :   int64_t u = Int64Base::GetInt(obj);
    6325               0 :   double d = uint32_t(INT64_LO(u));
    6326                 : 
    6327                 :   jsval result;
    6328               0 :   if (!JS_NewNumberValue(cx, d, &result))
    6329               0 :     return JS_FALSE;
    6330                 : 
    6331               0 :   JS_SET_RVAL(cx, vp, result);
    6332               0 :   return JS_TRUE;
    6333                 : }
    6334                 : 
    6335                 : JSBool
    6336               0 : Int64::Hi(JSContext* cx, unsigned argc, jsval* vp)
    6337                 : {
    6338               0 :   jsval* argv = JS_ARGV(cx, vp);
    6339               0 :   if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) ||
    6340               0 :       !Int64::IsInt64(JSVAL_TO_OBJECT(argv[0]))) {
    6341               0 :     JS_ReportError(cx, "hi takes one Int64 argument");
    6342               0 :     return JS_FALSE;
    6343                 :   }
    6344                 : 
    6345               0 :   JSObject* obj = JSVAL_TO_OBJECT(argv[0]);
    6346               0 :   int64_t u = Int64Base::GetInt(obj);
    6347               0 :   double d = int32_t(INT64_HI(u));
    6348                 : 
    6349                 :   jsval result;
    6350               0 :   if (!JS_NewNumberValue(cx, d, &result))
    6351               0 :     return JS_FALSE;
    6352                 : 
    6353               0 :   JS_SET_RVAL(cx, vp, result);
    6354               0 :   return JS_TRUE;
    6355                 : }
    6356                 : 
    6357                 : JSBool
    6358               0 : Int64::Join(JSContext* cx, unsigned argc, jsval* vp)
    6359                 : {
    6360               0 :   if (argc != 2) {
    6361               0 :     JS_ReportError(cx, "join takes two arguments");
    6362               0 :     return JS_FALSE;
    6363                 :   }
    6364                 : 
    6365               0 :   jsval* argv = JS_ARGV(cx, vp);
    6366                 :   int32_t hi;
    6367                 :   uint32_t lo;
    6368               0 :   if (!jsvalToInteger(cx, argv[0], &hi))
    6369               0 :     return TypeError(cx, "int32", argv[0]);
    6370               0 :   if (!jsvalToInteger(cx, argv[1], &lo))
    6371               0 :     return TypeError(cx, "uint32", argv[1]);
    6372                 : 
    6373               0 :   int64_t i = (int64_t(hi) << 32) + int64_t(lo);
    6374                 : 
    6375                 :   // Get Int64.prototype from the function's reserved slot.
    6376               0 :   JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
    6377                 : 
    6378               0 :   jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
    6379               0 :   JSObject* proto = JSVAL_TO_OBJECT(slot);
    6380               0 :   JS_ASSERT(JS_GetClass(proto) == &sInt64ProtoClass);
    6381                 : 
    6382               0 :   JSObject* result = Int64Base::Construct(cx, proto, i, false);
    6383               0 :   if (!result)
    6384               0 :     return JS_FALSE;
    6385                 : 
    6386               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    6387               0 :   return JS_TRUE;
    6388                 : }
    6389                 : 
    6390                 : JSBool
    6391               0 : UInt64::Construct(JSContext* cx,
    6392                 :                   unsigned argc,
    6393                 :                   jsval* vp)
    6394                 : {
    6395                 :   // Construct and return a new UInt64 object.
    6396               0 :   if (argc != 1) {
    6397               0 :     JS_ReportError(cx, "UInt64 takes one argument");
    6398               0 :     return JS_FALSE;
    6399                 :   }
    6400                 : 
    6401               0 :   jsval* argv = JS_ARGV(cx, vp);
    6402               0 :   uint64_t u = 0;
    6403               0 :   if (!jsvalToBigInteger(cx, argv[0], true, &u))
    6404               0 :     return TypeError(cx, "uint64", argv[0]);
    6405                 : 
    6406                 :   // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor.
    6407                 :   jsval slot;
    6408                 :   ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)),
    6409               0 :     "prototype", &slot));
    6410               0 :   JSObject* proto = JSVAL_TO_OBJECT(slot);
    6411               0 :   JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
    6412                 : 
    6413               0 :   JSObject* result = Int64Base::Construct(cx, proto, u, true);
    6414               0 :   if (!result)
    6415               0 :     return JS_FALSE;
    6416                 : 
    6417               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    6418               0 :   return JS_TRUE;
    6419                 : }
    6420                 : 
    6421                 : bool
    6422               0 : UInt64::IsUInt64(JSObject* obj)
    6423                 : {
    6424               0 :   return JS_GetClass(obj) == &sUInt64Class;
    6425                 : }
    6426                 : 
    6427                 : JSBool
    6428               0 : UInt64::ToString(JSContext* cx, unsigned argc, jsval* vp)
    6429                 : {
    6430               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    6431               0 :   if (!obj || !UInt64::IsUInt64(obj)) {
    6432               0 :     JS_ReportError(cx, "not a UInt64");
    6433               0 :     return JS_FALSE;
    6434                 :   }
    6435                 : 
    6436               0 :   return Int64Base::ToString(cx, obj, argc, vp, true);
    6437                 : }
    6438                 : 
    6439                 : JSBool
    6440               0 : UInt64::ToSource(JSContext* cx, unsigned argc, jsval* vp)
    6441                 : {
    6442               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
    6443               0 :   if (!obj || !UInt64::IsUInt64(obj)) {
    6444               0 :     JS_ReportError(cx, "not a UInt64");
    6445               0 :     return JS_FALSE;
    6446                 :   }
    6447                 : 
    6448               0 :   return Int64Base::ToSource(cx, obj, argc, vp, true);
    6449                 : }
    6450                 : 
    6451                 : JSBool
    6452               0 : UInt64::Compare(JSContext* cx, unsigned argc, jsval* vp)
    6453                 : {
    6454               0 :   jsval* argv = JS_ARGV(cx, vp);
    6455               0 :   if (argc != 2 ||
    6456               0 :       JSVAL_IS_PRIMITIVE(argv[0]) ||
    6457               0 :       JSVAL_IS_PRIMITIVE(argv[1]) ||
    6458               0 :       !UInt64::IsUInt64(JSVAL_TO_OBJECT(argv[0])) ||
    6459               0 :       !UInt64::IsUInt64(JSVAL_TO_OBJECT(argv[1]))) {
    6460               0 :     JS_ReportError(cx, "compare takes two UInt64 arguments");
    6461               0 :     return JS_FALSE;
    6462                 :   }
    6463                 : 
    6464               0 :   JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]);
    6465               0 :   JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]);
    6466                 : 
    6467               0 :   uint64_t u1 = Int64Base::GetInt(obj1);
    6468               0 :   uint64_t u2 = Int64Base::GetInt(obj2);
    6469                 : 
    6470               0 :   if (u1 == u2)
    6471               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0));
    6472               0 :   else if (u1 < u2)
    6473               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(-1));
    6474                 :   else
    6475               0 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(1));
    6476                 : 
    6477               0 :   return JS_TRUE;
    6478                 : }
    6479                 : 
    6480                 : JSBool
    6481               0 : UInt64::Lo(JSContext* cx, unsigned argc, jsval* vp)
    6482                 : {
    6483               0 :   jsval* argv = JS_ARGV(cx, vp);
    6484               0 :   if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) ||
    6485               0 :       !UInt64::IsUInt64(JSVAL_TO_OBJECT(argv[0]))) {
    6486               0 :     JS_ReportError(cx, "lo takes one UInt64 argument");
    6487               0 :     return JS_FALSE;
    6488                 :   }
    6489                 : 
    6490               0 :   JSObject* obj = JSVAL_TO_OBJECT(argv[0]);
    6491               0 :   uint64_t u = Int64Base::GetInt(obj);
    6492               0 :   double d = uint32_t(INT64_LO(u));
    6493                 : 
    6494                 :   jsval result;
    6495               0 :   if (!JS_NewNumberValue(cx, d, &result))
    6496               0 :     return JS_FALSE;
    6497                 : 
    6498               0 :   JS_SET_RVAL(cx, vp, result);
    6499               0 :   return JS_TRUE;
    6500                 : }
    6501                 : 
    6502                 : JSBool
    6503               0 : UInt64::Hi(JSContext* cx, unsigned argc, jsval* vp)
    6504                 : {
    6505               0 :   jsval* argv = JS_ARGV(cx, vp);
    6506               0 :   if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) ||
    6507               0 :       !UInt64::IsUInt64(JSVAL_TO_OBJECT(argv[0]))) {
    6508               0 :     JS_ReportError(cx, "hi takes one UInt64 argument");
    6509               0 :     return JS_FALSE;
    6510                 :   }
    6511                 : 
    6512               0 :   JSObject* obj = JSVAL_TO_OBJECT(argv[0]);
    6513               0 :   uint64_t u = Int64Base::GetInt(obj);
    6514               0 :   double d = uint32_t(INT64_HI(u));
    6515                 : 
    6516                 :   jsval result;
    6517               0 :   if (!JS_NewNumberValue(cx, d, &result))
    6518               0 :     return JS_FALSE;
    6519                 : 
    6520               0 :   JS_SET_RVAL(cx, vp, result);
    6521               0 :   return JS_TRUE;
    6522                 : }
    6523                 : 
    6524                 : JSBool
    6525               0 : UInt64::Join(JSContext* cx, unsigned argc, jsval* vp)
    6526                 : {
    6527               0 :   if (argc != 2) {
    6528               0 :     JS_ReportError(cx, "join takes two arguments");
    6529               0 :     return JS_FALSE;
    6530                 :   }
    6531                 : 
    6532               0 :   jsval* argv = JS_ARGV(cx, vp);
    6533                 :   uint32_t hi;
    6534                 :   uint32_t lo;
    6535               0 :   if (!jsvalToInteger(cx, argv[0], &hi))
    6536               0 :     return TypeError(cx, "uint32_t", argv[0]);
    6537               0 :   if (!jsvalToInteger(cx, argv[1], &lo))
    6538               0 :     return TypeError(cx, "uint32_t", argv[1]);
    6539                 : 
    6540               0 :   uint64_t u = (uint64_t(hi) << 32) + uint64_t(lo);
    6541                 : 
    6542                 :   // Get UInt64.prototype from the function's reserved slot.
    6543               0 :   JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
    6544                 : 
    6545               0 :   jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
    6546               0 :   JSObject* proto = JSVAL_TO_OBJECT(slot);
    6547               0 :   JS_ASSERT(JS_GetClass(proto) == &sUInt64ProtoClass);
    6548                 : 
    6549               0 :   JSObject* result = Int64Base::Construct(cx, proto, u, true);
    6550               0 :   if (!result)
    6551               0 :     return JS_FALSE;
    6552                 : 
    6553               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
    6554               0 :   return JS_TRUE;
    6555                 : }
    6556                 : 
    6557                 : }
    6558                 : }
    6559                 : 

Generated by: LCOV version 1.7