LCOV - code coverage report
Current view: directory - js/src/ctypes - CTypes.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2746 2239 81.5 %
Date: 2012-06-02 Functions: 547 417 76.2 %

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

Generated by: LCOV version 1.7