LCOV - app.info - js/src/ctypes/CTypes.cpp

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

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

Generated by: LCOV version 1.7