js/src/ctypes/CTypes.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef ctypes_CTypes_h
     7 #define ctypes_CTypes_h
     9 #include "ffi.h"
    10 #include "jsalloc.h"
    11 #include "prlink.h"
    13 #include "js/HashTable.h"
    14 #include "js/Vector.h"
    15 #include "vm/String.h"
    17 namespace js {
    18 namespace ctypes {
    20 /*******************************************************************************
    21 ** Utility classes
    22 *******************************************************************************/
    24 // Class that takes ownership of a pointer T*, and calls cx->delete_() or
    25 // cx->array_delete() upon destruction.
    26 template<class T>
    27 class AutoPtr {
    28 private:
    29   typedef AutoPtr<T> self_type;
    31 public:
    32   AutoPtr() : mPtr(nullptr) { }
    33   explicit AutoPtr(T* ptr) : mPtr(ptr) { }
    34   ~AutoPtr() { js_delete(mPtr); }
    36   T*   operator->()         { return mPtr; }
    37   bool operator!()          { return mPtr == nullptr; }
    38   T&   operator[](size_t i) { return *(mPtr + i); }
    39   // Note: we cannot safely provide an 'operator T*()', since this would allow
    40   // the compiler to perform implicit conversion from one AutoPtr to another
    41   // via the constructor AutoPtr(T*).
    43   T*   get()         { return mPtr; }
    44   void set(T* other) { JS_ASSERT(mPtr == nullptr); mPtr = other; }
    45   T*   forget()      { T* result = mPtr; mPtr = nullptr; return result; }
    47   self_type& operator=(T* rhs) { mPtr = rhs; return *this; }
    49 private:
    50   // Do not allow copy construction or assignment from another AutoPtr.
    51   AutoPtr(AutoPtr<T>&);
    52   self_type& operator=(AutoPtr<T>& rhs);
    54   T* mPtr;
    55 };
    57 // Container class for Vector, using SystemAllocPolicy.
    58 template<class T, size_t N = 0>
    59 class Array : public Vector<T, N, SystemAllocPolicy>
    60 {
    61   static_assert(!mozilla::IsSame<T, JS::Value>::value,
    62                 "use JS::AutoValueVector instead");
    63 };
    65 // String and AutoString classes, based on Vector.
    66 typedef Vector<jschar,  0, SystemAllocPolicy> String;
    67 typedef Vector<jschar, 64, SystemAllocPolicy> AutoString;
    68 typedef Vector<char,    0, SystemAllocPolicy> CString;
    69 typedef Vector<char,   64, SystemAllocPolicy> AutoCString;
    71 // Convenience functions to append, insert, and compare Strings.
    72 template <class T, size_t N, class AP, size_t ArrayLength>
    73 void
    74 AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
    75 {
    76   // Don't include the trailing '\0'.
    77   size_t alen = ArrayLength - 1;
    78   size_t vlen = v.length();
    79   if (!v.resize(vlen + alen))
    80     return;
    82   for (size_t i = 0; i < alen; ++i)
    83     v[i + vlen] = array[i];
    84 }
    86 template <class T, size_t N, size_t M, class AP>
    87 void
    88 AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
    89 {
    90   v.append(w.begin(), w.length());
    91 }
    93 template <size_t N, class AP>
    94 void
    95 AppendString(Vector<jschar, N, AP> &v, JSString* str)
    96 {
    97   JS_ASSERT(str);
    98   const jschar *chars = str->getChars(nullptr);
    99   if (!chars)
   100     return;
   101   v.append(chars, str->length());
   102 }
   104 template <size_t N, class AP>
   105 void
   106 AppendString(Vector<char, N, AP> &v, JSString* str)
   107 {
   108   JS_ASSERT(str);
   109   size_t vlen = v.length();
   110   size_t alen = str->length();
   111   if (!v.resize(vlen + alen))
   112     return;
   114   const jschar *chars = str->getChars(nullptr);
   115   if (!chars)
   116     return;
   118   for (size_t i = 0; i < alen; ++i)
   119     v[i + vlen] = char(chars[i]);
   120 }
   122 template <class T, size_t N, class AP, size_t ArrayLength>
   123 void
   124 PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
   125 {
   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;
   132   // Move vector data forward. This is safe since we've already resized.
   133   memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
   135   // Copy data to insert.
   136   for (size_t i = 0; i < alen; ++i)
   137     v[i] = array[i];
   138 }
   140 template <size_t N, class AP>
   141 void
   142 PrependString(Vector<jschar, N, AP> &v, JSString* str)
   143 {
   144   JS_ASSERT(str);
   145   size_t vlen = v.length();
   146   size_t alen = str->length();
   147   if (!v.resize(vlen + alen))
   148     return;
   150   const jschar *chars = str->getChars(nullptr);
   151   if (!chars)
   152     return;
   154   // Move vector data forward. This is safe since we've already resized.
   155   memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
   157   // Copy data to insert.
   158   memcpy(v.begin(), chars, alen * sizeof(jschar));
   159 }
   161 extern size_t
   162 GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
   163                             size_t charsLength);
   165 bool
   166 DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
   167                           char *dst, size_t *dstlenp);
   170 /*******************************************************************************
   171 ** Function and struct API definitions
   172 *******************************************************************************/
   174 MOZ_ALWAYS_INLINE void
   175 ASSERT_OK(bool ok)
   176 {
   177   JS_ASSERT(ok);
   178 }
   180 // for JS error reporting
   181 enum ErrorNum {
   182 #define MSG_DEF(name, number, count, exception, format) \
   183   name = number,
   184 #include "ctypes/ctypes.msg"
   185 #undef MSG_DEF
   186   CTYPESERR_LIMIT
   187 };
   189 /**
   190  * ABI constants that specify the calling convention to use.
   191  * ctypes.default_abi corresponds to the cdecl convention, and in almost all
   192  * cases is the correct choice. ctypes.stdcall_abi is provided for calling
   193  * stdcall functions on Win32, and implies stdcall symbol name decoration;
   194  * ctypes.winapi_abi is just stdcall but without decoration.
   195  */
   196 enum ABICode {
   197   ABI_DEFAULT,
   198   ABI_STDCALL,
   199   ABI_WINAPI,
   200   INVALID_ABI
   201 };
   203 enum TypeCode {
   204   TYPE_void_t,
   205 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
   206 #include "ctypes/typedefs.h"
   207   TYPE_pointer,
   208   TYPE_function,
   209   TYPE_array,
   210   TYPE_struct
   211 };
   213 // Descriptor of one field in a StructType. The name of the field is stored
   214 // as the key to the hash entry.
   215 struct FieldInfo
   216 {
   217   JS::Heap<JSObject*> mType;    // CType of the field
   218   size_t              mIndex;   // index of the field in the struct (first is 0)
   219   size_t              mOffset;  // offset of the field in the struct, in bytes
   220 };
   222 struct UnbarrieredFieldInfo
   223 {
   224   JSObject*           mType;    // CType of the field
   225   size_t              mIndex;   // index of the field in the struct (first is 0)
   226   size_t              mOffset;  // offset of the field in the struct, in bytes
   227 };
   228 static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo),
   229               "UnbarrieredFieldInfo should be the same as FieldInfo but with unbarriered mType");
   231 // Hash policy for FieldInfos.
   232 struct FieldHashPolicy : DefaultHasher<JSFlatString*>
   233 {
   234   typedef JSFlatString* Key;
   235   typedef Key Lookup;
   237   static uint32_t hash(const Lookup &l) {
   238     const jschar* s = l->chars();
   239     size_t n = l->length();
   240     uint32_t hash = 0;
   241     for (; n > 0; s++, n--)
   242       hash = hash * 33 + *s;
   243     return hash;
   244   }
   246   static bool match(const Key &k, const Lookup &l) {
   247     if (k == l)
   248       return true;
   250     if (k->length() != l->length())
   251       return false;
   253     return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
   254   }
   255 };
   257 typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
   259 // Descriptor of ABI, return type, argument types, and variadicity for a
   260 // FunctionType.
   261 struct FunctionInfo
   262 {
   263   // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
   264   // FunctionType::Call, when mIsVariadic. Not always consistent with
   265   // mFFITypes, due to lazy initialization when mIsVariadic.
   266   ffi_cif mCIF;
   268   // Calling convention of the function. Convert to ffi_abi using GetABI
   269   // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing.
   270   JS::Heap<JSObject*> mABI;
   272   // The CType of the value returned by the function.
   273   JS::Heap<JSObject*> mReturnType;
   275   // A fixed array of known parameter types, excluding any variadic
   276   // parameters (if mIsVariadic).
   277   Array<JS::Heap<JSObject*> > mArgTypes;
   279   // A variable array of ffi_type*s corresponding to both known parameter
   280   // types and dynamic (variadic) parameter types. Longer than mArgTypes
   281   // only if mIsVariadic.
   282   Array<ffi_type*> mFFITypes;
   284   // Flag indicating whether the function behaves like a C function with
   285   // ... as the final formal parameter.
   286   bool mIsVariadic;
   287 };
   289 // Parameters necessary for invoking a JS function from a C closure.
   290 struct ClosureInfo
   291 {
   292   JSContext* cx;                   // JSContext to use
   293   JSRuntime* rt;                   // Used in the destructor, where cx might have already
   294                                    // been GCed.
   295   JS::Heap<JSObject*> closureObj;  // CClosure object
   296   JS::Heap<JSObject*> typeObj;     // FunctionType describing the C function
   297   JS::Heap<JSObject*> thisObj;     // 'this' object to use for the JS function call
   298   JS::Heap<JSObject*> jsfnObj;     // JS function
   299   void* errResult;                 // Result that will be returned if the closure throws
   300   ffi_closure* closure;            // The C closure itself
   302   // Anything conditionally freed in the destructor should be initialized to
   303   // nullptr here.
   304   ClosureInfo(JSRuntime* runtime)
   305     : rt(runtime)
   306     , errResult(nullptr)
   307     , closure(nullptr)
   308   {}
   310   ~ClosureInfo() {
   311     if (closure)
   312       ffi_closure_free(closure);
   313     js_free(errResult);
   314   }
   315 };
   317 bool IsCTypesGlobal(HandleValue v);
   318 bool IsCTypesGlobal(JSObject* obj);
   320 JSCTypesCallbacks* GetCallbacks(JSObject* obj);
   322 /*******************************************************************************
   323 ** JSClass reserved slot definitions
   324 *******************************************************************************/
   326 enum CTypesGlobalSlot {
   327   SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct
   328   SLOT_ERRNO = 1,     // jsval for latest |errno|
   329   SLOT_LASTERROR = 2, // jsval for latest |GetLastError|, used only with Windows
   330   CTYPESGLOBAL_SLOTS
   331 };
   333 enum CABISlot {
   334   SLOT_ABICODE = 0, // ABICode of the CABI object
   335   CABI_SLOTS
   336 };
   338 enum CTypeProtoSlot {
   339   SLOT_POINTERPROTO      = 0,  // ctypes.PointerType.prototype object
   340   SLOT_ARRAYPROTO        = 1,  // ctypes.ArrayType.prototype object
   341   SLOT_STRUCTPROTO       = 2,  // ctypes.StructType.prototype object
   342   SLOT_FUNCTIONPROTO     = 3,  // ctypes.FunctionType.prototype object
   343   SLOT_CDATAPROTO        = 4,  // ctypes.CData.prototype object
   344   SLOT_POINTERDATAPROTO  = 5,  // common ancestor of all CData objects of PointerType
   345   SLOT_ARRAYDATAPROTO    = 6,  // common ancestor of all CData objects of ArrayType
   346   SLOT_STRUCTDATAPROTO   = 7,  // common ancestor of all CData objects of StructType
   347   SLOT_FUNCTIONDATAPROTO = 8,  // common ancestor of all CData objects of FunctionType
   348   SLOT_INT64PROTO        = 9,  // ctypes.Int64.prototype object
   349   SLOT_UINT64PROTO       = 10, // ctypes.UInt64.prototype object
   350   SLOT_CTYPES            = 11, // ctypes object
   351   SLOT_OURDATAPROTO      = 12, // the data prototype corresponding to this object
   352   CTYPEPROTO_SLOTS
   353 };
   355 enum CTypeSlot {
   356   SLOT_PROTO     = 0, // 'prototype' property of the CType object
   357   SLOT_TYPECODE  = 1, // TypeCode of the CType object
   358   SLOT_FFITYPE   = 2, // ffi_type representing the type
   359   SLOT_NAME      = 3, // name of the type
   360   SLOT_SIZE      = 4, // size of the type, in bytes
   361   SLOT_ALIGN     = 5, // alignment of the type, in bytes
   362   SLOT_PTR       = 6, // cached PointerType object for type.ptr
   363   // Note that some of the slots below can overlap, since they're for
   364   // mutually exclusive types.
   365   SLOT_TARGET_T  = 7, // (PointerTypes only) 'targetType' property
   366   SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property
   367   SLOT_LENGTH    = 8, // (ArrayTypes only) 'length' property
   368   SLOT_FIELDS    = 7, // (StructTypes only) 'fields' property
   369   SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table
   370   SLOT_FNINFO    = 7, // (FunctionTypes only) FunctionInfo struct
   371   SLOT_ARGS_T    = 8, // (FunctionTypes only) 'argTypes' property (cached)
   372   CTYPE_SLOTS
   373 };
   375 enum CDataSlot {
   376   SLOT_CTYPE    = 0, // CType object representing the underlying type
   377   SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
   378   SLOT_DATA     = 2, // pointer to a buffer containing the binary data
   379   SLOT_OWNS     = 3, // JSVAL_TRUE if this CData owns its own buffer
   380   CDATA_SLOTS
   381 };
   383 enum CClosureSlot {
   384   SLOT_CLOSUREINFO = 0, // ClosureInfo struct
   385   CCLOSURE_SLOTS
   386 };
   388 enum CDataFinalizerSlot {
   389   // The type of the value (a CType JSObject).
   390   // We hold it to permit ImplicitConvert and ToSource.
   391   SLOT_DATAFINALIZER_VALTYPE           = 0,
   392   // The type of the function used at finalization (a CType JSObject).
   393   // We hold it to permit |ToSource|.
   394   SLOT_DATAFINALIZER_CODETYPE          = 1,
   395   CDATAFINALIZER_SLOTS
   396 };
   398 enum TypeCtorSlot {
   399   SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
   400   // JSFunction objects always get exactly two slots.
   401 };
   403 enum Int64Slot {
   404   SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
   405   INT64_SLOTS
   406 };
   408 enum Int64FunctionSlot {
   409   SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
   410   // JSFunction objects always get exactly two slots.
   411 };
   413 /*******************************************************************************
   414 ** Object API definitions
   415 *******************************************************************************/
   417 namespace CType {
   418   JSObject* Create(JSContext* cx, HandleObject typeProto, HandleObject dataProto,
   419     TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType);
   421   JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName,
   422     JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type,
   423     jsval size, jsval align, ffi_type* ffiType);
   425   bool IsCType(JSObject* obj);
   426   bool IsCTypeProto(JSObject* obj);
   427   TypeCode GetTypeCode(JSObject* typeObj);
   428   bool TypesEqual(JSObject* t1, JSObject* t2);
   429   size_t GetSize(JSObject* obj);
   430   bool GetSafeSize(JSObject* obj, size_t* result);
   431   bool IsSizeDefined(JSObject* obj);
   432   size_t GetAlignment(JSObject* obj);
   433   ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
   434   JSString* GetName(JSContext* cx, HandleObject obj);
   435   JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot);
   436   JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
   437   JSCTypesCallbacks* GetCallbacksFromType(JSObject* obj);
   438 }
   440 namespace PointerType {
   441   JSObject* CreateInternal(JSContext* cx, HandleObject baseType);
   443   JSObject* GetBaseType(JSObject* obj);
   444 }
   446 namespace ArrayType {
   447   JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length,
   448     bool lengthDefined);
   450   JSObject* GetBaseType(JSObject* obj);
   451   size_t GetLength(JSObject* obj);
   452   bool GetSafeLength(JSObject* obj, size_t* result);
   453   ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
   454 }
   456 namespace StructType {
   457   bool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
   459   const FieldInfoHash* GetFieldInfo(JSObject* obj);
   460   const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
   461   JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
   462   ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
   463 }
   465 namespace FunctionType {
   466   JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype,
   467     jsval* argtypes, unsigned arglen);
   469   JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
   470     JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
   472   FunctionInfo* GetFunctionInfo(JSObject* obj);
   473   void BuildSymbolName(JSString* name, JSObject* typeObj,
   474     AutoCString& result);
   475 }
   477 namespace CClosure {
   478   JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj,
   479     HandleObject thisObj, jsval errVal, PRFuncPtr* fnptr);
   480 }
   482 namespace CData {
   483   JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject refObj,
   484     void* data, bool ownResult);
   486   JSObject* GetCType(JSObject* dataObj);
   487   void* GetData(JSObject* dataObj);
   488   bool IsCData(JSObject* obj);
   489   bool IsCData(HandleValue v);
   490   bool IsCDataProto(JSObject* obj);
   492   // Attached by JSAPI as the function 'ctypes.cast'
   493   bool Cast(JSContext* cx, unsigned argc, jsval* vp);
   494   // Attached by JSAPI as the function 'ctypes.getRuntime'
   495   bool GetRuntime(JSContext* cx, unsigned argc, jsval* vp);
   496 }
   498 namespace Int64 {
   499   bool IsInt64(JSObject* obj);
   500 }
   502 namespace UInt64 {
   503   bool IsUInt64(JSObject* obj);
   504 }
   506 }
   507 }
   509 #endif /* ctypes_CTypes_h */

mercurial