tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CTypes.h (19096B)


      1 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*-
      2 */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef ctypes_CTypes_h
      8 #define ctypes_CTypes_h
      9 
     10 #include "mozilla/Sprintf.h"
     11 #include "mozilla/Vector.h"
     12 
     13 #include "ffi.h"
     14 #include "prlink.h"
     15 
     16 #include "ctypes/typedefs.h"
     17 #include "gc/ZoneAllocator.h"
     18 #include "js/AllocPolicy.h"
     19 #include "js/GCHashTable.h"
     20 #include "js/UniquePtr.h"
     21 #include "js/Vector.h"
     22 #include "vm/JSObject.h"
     23 #include "vm/StringType.h"
     24 
     25 namespace JS {
     26 struct CTypesCallbacks;
     27 }  // namespace JS
     28 
     29 namespace js {
     30 namespace ctypes {
     31 
     32 /*******************************************************************************
     33 ** Utility classes
     34 *******************************************************************************/
     35 
     36 // CTypes builds a number of strings. StringBuilder allows repeated appending
     37 // with a single error check at the end. Only the Vector methods required for
     38 // building the string are exposed.
     39 
     40 template <class CharT, size_t N>
     41 class StringBuilder {
     42  Vector<CharT, N, SystemAllocPolicy> v;
     43 
     44  // Have any (OOM) errors been encountered while constructing this string?
     45  bool errored{false};
     46 
     47 #ifdef DEBUG
     48  // Have we finished building this string?
     49  bool finished{false};
     50 
     51  // Did we check for errors?
     52  mutable bool checked{false};
     53 #endif
     54 
     55 public:
     56  explicit operator bool() const {
     57 #ifdef DEBUG
     58    checked = true;
     59 #endif
     60    return !errored;
     61  }
     62 
     63  // Handle the result of modifying the string, by remembering the persistent
     64  // errored status.
     65  bool handle(bool result) {
     66    MOZ_ASSERT(!finished);
     67    if (!result) {
     68      errored = true;
     69    }
     70    return result;
     71  }
     72 
     73  bool resize(size_t n) { return handle(v.resize(n)); }
     74 
     75  CharT& operator[](size_t index) { return v[index]; }
     76  const CharT& operator[](size_t index) const { return v[index]; }
     77  size_t length() const { return v.length(); }
     78 
     79  template <typename U>
     80  [[nodiscard]] bool append(U&& u) {
     81    return handle(v.append(u));
     82  }
     83 
     84  template <typename U>
     85  [[nodiscard]] bool append(const U* begin, const U* end) {
     86    return handle(v.append(begin, end));
     87  }
     88 
     89  template <typename U>
     90  [[nodiscard]] bool append(const U* begin, size_t len) {
     91    return handle(v.append(begin, len));
     92  }
     93 
     94  CharT* begin() {
     95    MOZ_ASSERT(!finished);
     96    return v.begin();
     97  }
     98 
     99  // finish() produces the results of the string building, and is required as
    100  // the last thing before the string contents are used. The StringBuilder must
    101  // be checked for errors before calling this, however.
    102  Vector<CharT, N, SystemAllocPolicy>&& finish() {
    103    MOZ_ASSERT(!errored);
    104    MOZ_ASSERT(!finished);
    105    MOZ_ASSERT(checked);
    106 #ifdef DEBUG
    107    finished = true;
    108 #endif
    109    return std::move(v);
    110  }
    111 };
    112 
    113 // Note that these strings do not have any inline storage, because we use move
    114 // constructors to pass the data around and inline storage would necessitate
    115 // copying.
    116 typedef StringBuilder<char16_t, 0> AutoString;
    117 typedef StringBuilder<char, 0> AutoCString;
    118 
    119 typedef Vector<char16_t, 0, SystemAllocPolicy> AutoStringChars;
    120 typedef Vector<char, 0, SystemAllocPolicy> AutoCStringChars;
    121 
    122 // Convenience functions to append, insert, and compare Strings.
    123 template <class T, size_t N, size_t ArrayLength>
    124 void AppendString(JSContext* cx, StringBuilder<T, N>& v,
    125                  const char (&array)[ArrayLength]) {
    126  // Don't include the trailing '\0'.
    127  size_t alen = ArrayLength - 1;
    128  size_t vlen = v.length();
    129  if (!v.resize(vlen + alen)) {
    130    return;
    131  }
    132 
    133  for (size_t i = 0; i < alen; ++i) {
    134    v[i + vlen] = array[i];
    135  }
    136 }
    137 
    138 template <class T, size_t N>
    139 void AppendChars(StringBuilder<T, N>& v, const char c, size_t count) {
    140  size_t vlen = v.length();
    141  if (!v.resize(vlen + count)) {
    142    return;
    143  }
    144 
    145  for (size_t i = 0; i < count; ++i) {
    146    v[i + vlen] = c;
    147  }
    148 }
    149 
    150 template <class T, size_t N>
    151 void AppendUInt(StringBuilder<T, N>& v, unsigned n) {
    152  char array[16];
    153  size_t alen = SprintfLiteral(array, "%u", n);
    154  size_t vlen = v.length();
    155  if (!v.resize(vlen + alen)) {
    156    return;
    157  }
    158 
    159  for (size_t i = 0; i < alen; ++i) {
    160    v[i + vlen] = array[i];
    161  }
    162 }
    163 
    164 template <class T, size_t N, size_t M, class AP>
    165 void AppendString(JSContext* cx, StringBuilder<T, N>& v,
    166                  mozilla::Vector<T, M, AP>& w) {
    167  if (!v.append(w.begin(), w.length())) {
    168    return;
    169  }
    170 }
    171 
    172 template <size_t N>
    173 void AppendString(JSContext* cx, StringBuilder<char16_t, N>& v, JSString* str) {
    174  MOZ_ASSERT(str);
    175  JSLinearString* linear = str->ensureLinear(cx);
    176  if (!linear) {
    177    return;
    178  }
    179  JS::AutoCheckCannotGC nogc;
    180  if (linear->hasLatin1Chars()) {
    181    if (!v.append(linear->latin1Chars(nogc), linear->length())) {
    182      return;
    183    }
    184  } else {
    185    if (!v.append(linear->twoByteChars(nogc), linear->length())) {
    186      return;
    187    }
    188  }
    189 }
    190 
    191 template <size_t N>
    192 void AppendString(JSContext* cx, StringBuilder<char, N>& v, JSString* str) {
    193  MOZ_ASSERT(str);
    194  size_t vlen = v.length();
    195  size_t alen = str->length();
    196  if (!v.resize(vlen + alen)) {
    197    return;
    198  }
    199 
    200  JSLinearString* linear = str->ensureLinear(cx);
    201  if (!linear) {
    202    return;
    203  }
    204 
    205  JS::AutoCheckCannotGC nogc;
    206  if (linear->hasLatin1Chars()) {
    207    const Latin1Char* chars = linear->latin1Chars(nogc);
    208    for (size_t i = 0; i < alen; ++i) {
    209      v[i + vlen] = char(chars[i]);
    210    }
    211  } else {
    212    const char16_t* chars = linear->twoByteChars(nogc);
    213    for (size_t i = 0; i < alen; ++i) {
    214      v[i + vlen] = char(chars[i]);
    215    }
    216  }
    217 }
    218 
    219 template <class T, size_t N, size_t ArrayLength>
    220 void PrependString(JSContext* cx, StringBuilder<T, N>& v,
    221                   const char (&array)[ArrayLength]) {
    222  // Don't include the trailing '\0'.
    223  size_t alen = ArrayLength - 1;
    224  size_t vlen = v.length();
    225  if (!v.resize(vlen + alen)) {
    226    return;
    227  }
    228 
    229  // Move vector data forward. This is safe since we've already resized.
    230  memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
    231 
    232  // Copy data to insert.
    233  for (size_t i = 0; i < alen; ++i) {
    234    v[i] = array[i];
    235  }
    236 }
    237 
    238 template <size_t N>
    239 void PrependString(JSContext* cx, StringBuilder<char16_t, N>& v,
    240                   JSString* str) {
    241  MOZ_ASSERT(str);
    242  size_t vlen = v.length();
    243  size_t alen = str->length();
    244  if (!v.resize(vlen + alen)) {
    245    return;
    246  }
    247 
    248  JSLinearString* linear = str->ensureLinear(cx);
    249  if (!linear) {
    250    return;
    251  }
    252 
    253  // Move vector data forward. This is safe since we've already resized.
    254  memmove(v.begin() + alen, v.begin(), vlen * sizeof(char16_t));
    255 
    256  // Copy data to insert.
    257  CopyChars(v.begin(), *linear);
    258 }
    259 
    260 [[nodiscard]] bool ReportErrorIfUnpairedSurrogatePresent(JSContext* cx,
    261                                                         JSLinearString* str);
    262 
    263 [[nodiscard]] JSObject* GetThisObject(JSContext* cx, const CallArgs& args,
    264                                      const char* msg);
    265 
    266 /*******************************************************************************
    267 ** Function and struct API definitions
    268 *******************************************************************************/
    269 
    270 // for JS error reporting
    271 enum ErrorNum {
    272 #define MSG_DEF(name, count, exception, format) name,
    273 #include "ctypes/ctypes.msg"
    274 #undef MSG_DEF
    275  CTYPESERR_LIMIT
    276 };
    277 
    278 /**
    279 * ABI constants that specify the calling convention to use.
    280 * ctypes.default_abi corresponds to the cdecl convention, and in almost all
    281 * cases is the correct choice. ctypes.stdcall_abi is provided for calling
    282 * stdcall functions on Win32, and implies stdcall symbol name decoration;
    283 * ctypes.winapi_abi is just stdcall but without decoration.
    284 */
    285 enum ABICode {
    286  ABI_DEFAULT,
    287  ABI_STDCALL,
    288  ABI_THISCALL,
    289  ABI_WINAPI,
    290  INVALID_ABI
    291 };
    292 
    293 enum TypeCode {
    294  TYPE_void_t,
    295 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
    296  CTYPES_FOR_EACH_TYPE(DEFINE_TYPE)
    297 #undef DEFINE_TYPE
    298      TYPE_pointer,
    299  TYPE_function,
    300  TYPE_array,
    301  TYPE_struct
    302 };
    303 
    304 // Descriptor of one field in a StructType. The name of the field is stored
    305 // as the key to the hash entry.
    306 struct FieldInfo {
    307  HeapPtr<JSObject*> mType;  // CType of the field
    308  size_t mIndex;             // index of the field in the struct (first is 0)
    309  size_t mOffset;            // offset of the field in the struct, in bytes
    310 
    311  void trace(JSTracer* trc) { TraceEdge(trc, &mType, "fieldType"); }
    312 };
    313 
    314 struct UnbarrieredFieldInfo {
    315  JSObject* mType;  // CType of the field
    316  size_t mIndex;    // index of the field in the struct (first is 0)
    317  size_t mOffset;   // offset of the field in the struct, in bytes
    318 };
    319 static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo),
    320              "UnbarrieredFieldInfo should be the same as FieldInfo but with "
    321              "unbarriered mType");
    322 
    323 // Hash policy for FieldInfos.
    324 struct FieldHashPolicy {
    325  using Key = JSLinearString*;
    326  using Lookup = Key;
    327 
    328  static HashNumber hash(const Lookup& l) { return js::HashStringChars(l); }
    329 
    330  static bool match(const Key& k, const Lookup& l) {
    331    return js::EqualStrings(k, l);
    332  }
    333 };
    334 
    335 using FieldInfoHash = GCHashMap<js::HeapPtr<JSLinearString*>, FieldInfo,
    336                                FieldHashPolicy, CellAllocPolicy>;
    337 
    338 // Descriptor of ABI, return type, argument types, and variadicity for a
    339 // FunctionType.
    340 struct FunctionInfo {
    341  explicit FunctionInfo(JS::Zone* zone) : mArgTypes(zone), mFFITypes(zone) {}
    342 
    343  // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
    344  // FunctionType::Call, when mIsVariadic. Not always consistent with
    345  // mFFITypes, due to lazy initialization when mIsVariadic.
    346  ffi_cif mCIF;
    347 
    348  // Calling convention of the function. Convert to ffi_abi using GetABI
    349  // and ObjectValue. Stored as a JSObject* for ease of tracing.
    350  HeapPtr<JSObject*> mABI;
    351 
    352  // The CType of the value returned by the function.
    353  HeapPtr<JSObject*> mReturnType;
    354 
    355  // A fixed array of known parameter types, excluding any variadic
    356  // parameters (if mIsVariadic).
    357  GCVector<HeapPtr<JSObject*>, 0, CellAllocPolicy> mArgTypes;
    358 
    359  // A variable array of ffi_type*s corresponding to both known parameter
    360  // types and dynamic (variadic) parameter types. Longer than mArgTypes
    361  // only if mIsVariadic.
    362  Vector<ffi_type*, 0, CellAllocPolicy> mFFITypes;
    363 
    364  // Flag indicating whether the function behaves like a C function with
    365  // ... as the final formal parameter.
    366  bool mIsVariadic;
    367 };
    368 
    369 // Parameters necessary for invoking a JS function from a C closure.
    370 struct ClosureInfo {
    371  JSContext* cx;
    372  HeapPtr<JSObject*> closureObj;  // CClosure object
    373  HeapPtr<JSObject*> typeObj;     // FunctionType describing the C function
    374  HeapPtr<JSObject*> thisObj;  // 'this' object to use for the JS function call
    375  HeapPtr<JSObject*> jsfnObj;  // JS function
    376  void* errResult;       // Result that will be returned if the closure throws
    377  ffi_closure* closure;  // The C closure itself
    378 
    379  // Anything conditionally freed in the destructor should be initialized to
    380  // nullptr here.
    381  explicit ClosureInfo(JSContext* context)
    382      : cx(context), errResult(nullptr), closure(nullptr) {}
    383 
    384  ~ClosureInfo() {
    385    if (closure) {
    386      ffi_closure_free(closure);
    387    }
    388    js_free(errResult);
    389  }
    390 };
    391 
    392 bool IsCTypesGlobal(HandleValue v);
    393 bool IsCTypesGlobal(JSObject* obj);
    394 
    395 const JS::CTypesCallbacks* GetCallbacks(JSObject* obj);
    396 
    397 /*******************************************************************************
    398 ** JSClass reserved slot definitions
    399 *******************************************************************************/
    400 
    401 enum CTypesGlobalSlot {
    402  SLOT_CALLBACKS = 0,  // pointer to JS::CTypesCallbacks struct
    403  SLOT_ERRNO = 1,      // Value for latest |errno|
    404  SLOT_LASTERROR =
    405      2,  // Value for latest |GetLastError|, used only with Windows
    406  CTYPESGLOBAL_SLOTS
    407 };
    408 
    409 enum CABISlot {
    410  SLOT_ABICODE = 0,  // ABICode of the CABI object
    411  CABI_SLOTS
    412 };
    413 
    414 enum CTypeProtoSlot {
    415  SLOT_POINTERPROTO = 0,   // ctypes.PointerType.prototype object
    416  SLOT_ARRAYPROTO = 1,     // ctypes.ArrayType.prototype object
    417  SLOT_STRUCTPROTO = 2,    // ctypes.StructType.prototype object
    418  SLOT_FUNCTIONPROTO = 3,  // ctypes.FunctionType.prototype object
    419  SLOT_CDATAPROTO = 4,     // ctypes.CData.prototype object
    420  SLOT_POINTERDATAPROTO =
    421      5,  // common ancestor of all CData objects of PointerType
    422  SLOT_ARRAYDATAPROTO = 6,  // common ancestor of all CData objects of ArrayType
    423  SLOT_STRUCTDATAPROTO =
    424      7,  // common ancestor of all CData objects of StructType
    425  SLOT_FUNCTIONDATAPROTO =
    426      8,                // common ancestor of all CData objects of FunctionType
    427  SLOT_INT64PROTO = 9,  // ctypes.Int64.prototype object
    428  SLOT_UINT64PROTO = 10,   // ctypes.UInt64.prototype object
    429  SLOT_CTYPES = 11,        // ctypes object
    430  SLOT_OURDATAPROTO = 12,  // the data prototype corresponding to this object
    431  CTYPEPROTO_SLOTS
    432 };
    433 
    434 enum CTypeSlot {
    435  SLOT_PROTO = 0,     // 'prototype' property of the CType object
    436  SLOT_TYPECODE = 1,  // TypeCode of the CType object
    437  SLOT_FFITYPE = 2,   // ffi_type representing the type
    438  SLOT_NAME = 3,      // name of the type
    439  SLOT_SIZE = 4,      // size of the type, in bytes
    440  SLOT_ALIGN = 5,     // alignment of the type, in bytes
    441  SLOT_PTR = 6,       // cached PointerType object for type.ptr
    442  // Note that some of the slots below can overlap, since they're for
    443  // mutually exclusive types.
    444  SLOT_TARGET_T = 7,   // (PointerTypes only) 'targetType' property
    445  SLOT_ELEMENT_T = 7,  // (ArrayTypes only) 'elementType' property
    446  SLOT_LENGTH = 8,     // (ArrayTypes only) 'length' property
    447  SLOT_FIELDS = 7,     // (StructTypes only) 'fields' property
    448  SLOT_FIELDINFO = 8,  // (StructTypes only) FieldInfoHash table
    449  SLOT_FNINFO = 7,     // (FunctionTypes only) FunctionInfo struct
    450  SLOT_ARGS_T = 8,     // (FunctionTypes only) 'argTypes' property (cached)
    451  CTYPE_SLOTS
    452 };
    453 
    454 enum CDataSlot {
    455  SLOT_CTYPE = 0,     // CType object representing the underlying type
    456  SLOT_REFERENT = 1,  // JSObject this object must keep alive, if any
    457  SLOT_DATA = 2,      // pointer to a buffer containing the binary data
    458  SLOT_OWNS = 3,      // TrueValue() if this CData owns its own buffer
    459  SLOT_FUNNAME = 4,   // JSString representing the function name
    460  CDATA_SLOTS
    461 };
    462 
    463 enum CClosureSlot {
    464  SLOT_CLOSUREINFO = 0,  // ClosureInfo struct
    465  CCLOSURE_SLOTS
    466 };
    467 
    468 enum CDataFinalizerSlot {
    469  // PrivateValue storing CDataFinalizer::Private* pointer or UndefinedValue.
    470  SLOT_DATAFINALIZER_PRIVATE = 0,
    471  // The type of the value (a CType JSObject).
    472  // We hold it to permit ImplicitConvert and ToSource.
    473  SLOT_DATAFINALIZER_VALTYPE = 1,
    474  // The type of the function used at finalization (a CType JSObject).
    475  // We hold it to permit |ToSource|.
    476  SLOT_DATAFINALIZER_CODETYPE = 2,
    477  CDATAFINALIZER_SLOTS
    478 };
    479 
    480 enum TypeCtorSlot {
    481  SLOT_FN_CTORPROTO = 0  // ctypes.{Pointer,Array,Struct}Type.prototype
    482  // JSFunction objects always get exactly two slots.
    483 };
    484 
    485 enum Int64Slot {
    486  SLOT_INT64 = 0,  // pointer to a 64-bit buffer containing the integer
    487  INT64_SLOTS
    488 };
    489 
    490 enum Int64FunctionSlot {
    491  SLOT_FN_INT64PROTO = 0  // ctypes.{Int64,UInt64}.prototype object
    492  // JSFunction objects always get exactly two slots.
    493 };
    494 
    495 /*******************************************************************************
    496 ** Object API definitions
    497 *******************************************************************************/
    498 
    499 namespace CType {
    500 JSObject* Create(JSContext* cx, HandleObject typeProto, HandleObject dataProto,
    501                 TypeCode type, JSString* name, HandleValue size,
    502                 HandleValue align, ffi_type* ffiType);
    503 
    504 JSObject* DefineBuiltin(JSContext* cx, HandleObject ctypesObj,
    505                        const char* propName, JSObject* typeProto,
    506                        JSObject* dataProto, const char* name, TypeCode type,
    507                        HandleValue size, HandleValue align, ffi_type* ffiType);
    508 
    509 bool IsCType(JSObject* obj);
    510 bool IsCTypeProto(JSObject* obj);
    511 TypeCode GetTypeCode(JSObject* typeObj);
    512 bool TypesEqual(JSObject* t1, JSObject* t2);
    513 size_t GetSize(JSObject* obj);
    514 [[nodiscard]] bool GetSafeSize(JSObject* obj, size_t* result);
    515 bool IsSizeDefined(JSObject* obj);
    516 size_t GetAlignment(JSObject* obj);
    517 ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
    518 JSString* GetName(JSContext* cx, HandleObject obj);
    519 JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot);
    520 JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
    521 const JS::CTypesCallbacks* GetCallbacksFromType(JSObject* obj);
    522 }  // namespace CType
    523 
    524 namespace PointerType {
    525 JSObject* CreateInternal(JSContext* cx, HandleObject baseType);
    526 
    527 JSObject* GetBaseType(JSObject* obj);
    528 }  // namespace PointerType
    529 
    530 using UniquePtrFFIType = UniquePtr<ffi_type>;
    531 
    532 namespace ArrayType {
    533 JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length,
    534                         bool lengthDefined);
    535 
    536 JSObject* GetBaseType(JSObject* obj);
    537 size_t GetLength(JSObject* obj);
    538 [[nodiscard]] bool GetSafeLength(JSObject* obj, size_t* result);
    539 UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj);
    540 }  // namespace ArrayType
    541 
    542 namespace StructType {
    543 [[nodiscard]] bool DefineInternal(JSContext* cx, JSObject* typeObj,
    544                                  JSObject* fieldsObj);
    545 
    546 const FieldInfoHash* GetFieldInfo(JSObject* obj);
    547 const FieldInfo* LookupField(JSContext* cx, JSObject* obj,
    548                             JSLinearString* name);
    549 JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
    550 UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj);
    551 }  // namespace StructType
    552 
    553 namespace FunctionType {
    554 JSObject* CreateInternal(JSContext* cx, HandleValue abi, HandleValue rtype,
    555                         const HandleValueArray& args);
    556 
    557 JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
    558                              JSObject* refObj, PRFuncPtr fnptr,
    559                              JSObject* result);
    560 
    561 FunctionInfo* GetFunctionInfo(JSObject* obj);
    562 void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
    563                     AutoCString& result);
    564 }  // namespace FunctionType
    565 
    566 namespace CClosure {
    567 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj,
    568                 HandleObject thisObj, HandleValue errVal, PRFuncPtr* fnptr);
    569 }  // namespace CClosure
    570 
    571 namespace CData {
    572 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject refObj,
    573                 void* data, bool ownResult);
    574 
    575 JSObject* GetCType(JSObject* dataObj);
    576 void* GetData(JSObject* dataObj);
    577 bool IsCData(JSObject* obj);
    578 bool IsCDataMaybeUnwrap(MutableHandleObject obj);
    579 bool IsCData(HandleValue v);
    580 bool IsCDataProto(JSObject* obj);
    581 
    582 // Attached by JSAPI as the function 'ctypes.cast'
    583 [[nodiscard]] bool Cast(JSContext* cx, unsigned argc, Value* vp);
    584 // Attached by JSAPI as the function 'ctypes.getRuntime'
    585 [[nodiscard]] bool GetRuntime(JSContext* cx, unsigned argc, Value* vp);
    586 }  // namespace CData
    587 
    588 namespace Int64 {
    589 bool IsInt64(JSObject* obj);
    590 }  // namespace Int64
    591 
    592 namespace UInt64 {
    593 bool IsUInt64(JSObject* obj);
    594 }  // namespace UInt64
    595 
    596 }  // namespace ctypes
    597 }  // namespace js
    598 
    599 #endif /* ctypes_CTypes_h */