Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / ctypes / CTypes.h
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 #ifndef CTYPES_H
40 #define CTYPES_H
41
42 #include "jscntxt.h"
43 #include "jsapi.h"
44 #include "jshashtable.h"
45 #include "prlink.h"
46 #include "ffi.h"
47
48 namespace js {
49 namespace ctypes {
50
51 /*******************************************************************************
52 ** Utility classes
53 *******************************************************************************/
54
55 template<class T>
56 class OperatorDelete
57 {
58 public:
59   static void destroy(T* ptr) { js_delete(ptr); }
60 };
61
62 template<class T>
63 class OperatorArrayDelete
64 {
65 public:
66   static void destroy(T* ptr) { js_array_delete(ptr); }
67 };
68
69 // Class that takes ownership of a pointer T*, and calls js_delete() or
70 // js_array_delete() upon destruction.
71 template<class T, class DeleteTraits = OperatorDelete<T> >
72 class AutoPtr {
73 private:
74   typedef AutoPtr<T, DeleteTraits> self_type;
75
76 public:
77   // An AutoPtr variant that calls js_array_delete() instead.
78   typedef AutoPtr<T, OperatorArrayDelete<T> > Array;
79
80   AutoPtr() : mPtr(NULL) { }
81   explicit AutoPtr(T* ptr) : mPtr(ptr) { }
82   ~AutoPtr() { DeleteTraits::destroy(mPtr); }
83
84   T*   operator->()         { return mPtr; }
85   bool operator!()          { return mPtr == NULL; }
86   T&   operator[](size_t i) { return *(mPtr + i); }
87   // Note: we cannot safely provide an 'operator T*()', since this would allow
88   // the compiler to perform implicit conversion from one AutoPtr to another
89   // via the constructor AutoPtr(T*).
90
91   T*   get()         { return mPtr; }
92   void set(T* other) { JS_ASSERT(mPtr == NULL); mPtr = other; }
93   T*   forget()      { T* result = mPtr; mPtr = NULL; return result; }
94
95   self_type& operator=(T* rhs) { mPtr = rhs; return *this; }
96
97 private:
98   // Do not allow copy construction or assignment from another AutoPtr.
99   template<class U> AutoPtr(AutoPtr<T, U>&);
100   template<class U> self_type& operator=(AutoPtr<T, U>& rhs);
101
102   T* mPtr;
103 };
104
105 // Container class for Vector, using SystemAllocPolicy.
106 template<class T, size_t N = 0>
107 class Array : public Vector<T, N, SystemAllocPolicy>
108 {
109 };
110
111 // String and AutoString classes, based on Vector.
112 typedef Vector<jschar,  0, SystemAllocPolicy> String;
113 typedef Vector<jschar, 64, SystemAllocPolicy> AutoString;
114 typedef Vector<char,    0, SystemAllocPolicy> CString;
115 typedef Vector<char,   64, SystemAllocPolicy> AutoCString;
116
117 // Convenience functions to append, insert, and compare Strings.
118 template <class T, size_t N, class AP, size_t ArrayLength>
119 void
120 AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
121 {
122   // Don't include the trailing '\0'.
123   size_t alen = ArrayLength - 1;
124   size_t vlen = v.length();
125   if (!v.resize(vlen + alen))
126     return;
127
128   for (size_t i = 0; i < alen; ++i)
129     v[i + vlen] = array[i];
130 }
131
132 template <class T, size_t N, size_t M, class AP>
133 void
134 AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
135 {
136   v.append(w.begin(), w.length());
137 }
138
139 template <size_t N, class AP>
140 void
141 AppendString(Vector<jschar, N, AP> &v, JSString* str)
142 {
143   JS_ASSERT(str);
144   const jschar *chars = str->getChars(NULL);
145   if (!chars)
146     return;
147   v.append(chars, str->length());
148 }
149
150 template <size_t N, class AP>
151 void
152 AppendString(Vector<char, N, AP> &v, JSString* str)
153 {
154   JS_ASSERT(str);
155   size_t vlen = v.length();
156   size_t alen = str->length();
157   if (!v.resize(vlen + alen))
158     return;
159
160   const jschar *chars = str->getChars(NULL);
161   if (!chars)
162     return;
163
164   for (size_t i = 0; i < alen; ++i)
165     v[i + vlen] = char(chars[i]);
166 }
167
168 template <class T, size_t N, class AP, size_t ArrayLength>
169 void
170 PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
171 {
172   // Don't include the trailing '\0'.
173   size_t alen = ArrayLength - 1;
174   size_t vlen = v.length();
175   if (!v.resize(vlen + alen))
176     return;
177
178   // Move vector data forward. This is safe since we've already resized.
179   memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
180
181   // Copy data to insert.
182   for (size_t i = 0; i < alen; ++i)
183     v[i] = array[i];
184 }
185
186 template <size_t N, class AP>
187 void
188 PrependString(Vector<jschar, N, AP> &v, JSString* str)
189 {
190   JS_ASSERT(str);
191   size_t vlen = v.length();
192   size_t alen = str->length();
193   if (!v.resize(vlen + alen))
194     return;
195
196   const jschar *chars = str->getChars(NULL);
197   if (!chars)
198     return;
199
200   // Move vector data forward. This is safe since we've already resized.
201   memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
202
203   // Copy data to insert.
204   memcpy(v.begin(), chars, alen * sizeof(jschar));
205 }
206
207 /*******************************************************************************
208 ** Function and struct API definitions
209 *******************************************************************************/
210
211 JS_ALWAYS_INLINE void
212 ASSERT_OK(JSBool ok)
213 {
214   JS_ASSERT(ok);
215 }
216
217 // for JS error reporting
218 enum ErrorNum {
219 #define MSG_DEF(name, number, count, exception, format) \
220   name = number,
221 #include "ctypes.msg"
222 #undef MSG_DEF
223   CTYPESERR_LIMIT
224 };
225
226 const JSErrorFormatString*
227 GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
228 JSBool TypeError(JSContext* cx, const char* expected, jsval actual);
229
230 /**
231  * ABI constants that specify the calling convention to use.
232  * ctypes.default_abi corresponds to the cdecl convention, and in almost all
233  * cases is the correct choice. ctypes.stdcall_abi is provided for calling
234  * stdcall functions on Win32, and implies stdcall symbol name decoration;
235  * ctypes.winapi_abi is just stdcall but without decoration.
236  */
237 enum ABICode {
238   ABI_DEFAULT,
239   ABI_STDCALL,
240   ABI_WINAPI,
241   INVALID_ABI
242 };
243
244 enum TypeCode {
245   TYPE_void_t,
246 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
247 #include "typedefs.h"
248   TYPE_pointer,
249   TYPE_function,
250   TYPE_array,
251   TYPE_struct
252 };
253
254 // Descriptor of one field in a StructType. The name of the field is stored
255 // as the key to the hash entry.
256 struct FieldInfo
257 {
258   JSObject* mType;    // CType of the field
259   size_t    mIndex;   // index of the field in the struct (first is 0)
260   size_t    mOffset;  // offset of the field in the struct, in bytes
261 };
262
263 // Hash policy for FieldInfos.
264 struct FieldHashPolicy
265 {
266   typedef JSFlatString* Key;
267   typedef Key Lookup;
268
269   static uint32 hash(const Lookup &l) {
270     const jschar* s = l->chars();
271     size_t n = l->length();
272     uint32 hash = 0;
273     for (; n > 0; s++, n--)
274       hash = hash * 33 + *s;
275     return hash;
276   }
277
278   static JSBool match(const Key &k, const Lookup &l) {
279     if (k == l)
280       return true;
281
282     if (k->length() != l->length())
283       return false;
284
285     return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
286   }
287 };
288
289 typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
290
291 // Descriptor of ABI, return type, argument types, and variadicity for a
292 // FunctionType.
293 struct FunctionInfo
294 {
295   // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
296   // FunctionType::Call, when mIsVariadic. Not always consistent with
297   // mFFITypes, due to lazy initialization when mIsVariadic.
298   ffi_cif mCIF;
299
300   // Calling convention of the function. Convert to ffi_abi using GetABI
301   // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing.
302   JSObject* mABI;                
303
304   // The CType of the value returned by the function.
305   JSObject* mReturnType;
306
307   // A fixed array of known parameter types, excluding any variadic
308   // parameters (if mIsVariadic).
309   Array<JSObject*> mArgTypes; 
310
311   // A variable array of ffi_type*s corresponding to both known parameter
312   // types and dynamic (variadic) parameter types. Longer than mArgTypes
313   // only if mIsVariadic.
314   Array<ffi_type*> mFFITypes;
315
316   // Flag indicating whether the function behaves like a C function with
317   // ... as the final formal parameter.
318   bool mIsVariadic;
319 };
320
321 // Parameters necessary for invoking a JS function from a C closure.
322 struct ClosureInfo
323 {
324   JSContext* cx;         // JSContext to use
325   JSObject* closureObj;  // CClosure object
326   JSObject* typeObj;     // FunctionType describing the C function
327   JSObject* thisObj;     // 'this' object to use for the JS function call
328   JSObject* jsfnObj;     // JS function
329   ffi_closure* closure;  // The C closure itself
330 #ifdef DEBUG
331   jsword cxThread;       // The thread on which the context may be used
332 #endif
333 };
334
335 bool IsCTypesGlobal(JSContext* cx, JSObject* obj);
336
337 JSCTypesCallbacks* GetCallbacks(JSContext* cx, JSObject* obj);
338
339 JSBool InitTypeClasses(JSContext* cx, JSObject* parent);
340
341 JSBool ConvertToJS(JSContext* cx, JSObject* typeObj, JSObject* dataObj,
342   void* data, bool wantPrimitive, bool ownResult, jsval* result);
343
344 JSBool ImplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
345   void* buffer, bool isArgument, bool* freePointer);
346
347 JSBool ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
348   void* buffer);
349
350 /*******************************************************************************
351 ** JSClass reserved slot definitions
352 *******************************************************************************/
353
354 enum CTypesGlobalSlot {
355   SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct
356   CTYPESGLOBAL_SLOTS
357 };
358
359 enum CABISlot {
360   SLOT_ABICODE = 0, // ABICode of the CABI object
361   CABI_SLOTS
362 };
363
364 enum CTypeProtoSlot {
365   SLOT_POINTERPROTO      = 0,  // ctypes.PointerType.prototype object
366   SLOT_ARRAYPROTO        = 1,  // ctypes.ArrayType.prototype object
367   SLOT_STRUCTPROTO       = 2,  // ctypes.StructType.prototype object
368   SLOT_FUNCTIONPROTO     = 3,  // ctypes.FunctionType.prototype object
369   SLOT_CDATAPROTO        = 4,  // ctypes.CData.prototype object
370   SLOT_POINTERDATAPROTO  = 5,  // common ancestor of all CData objects of PointerType
371   SLOT_ARRAYDATAPROTO    = 6,  // common ancestor of all CData objects of ArrayType
372   SLOT_STRUCTDATAPROTO   = 7,  // common ancestor of all CData objects of StructType
373   SLOT_FUNCTIONDATAPROTO = 8,  // common ancestor of all CData objects of FunctionType
374   SLOT_INT64PROTO        = 9,  // ctypes.Int64.prototype object
375   SLOT_UINT64PROTO       = 10, // ctypes.UInt64.prototype object
376   SLOT_CLOSURECX         = 11, // JSContext for use with FunctionType closures
377   CTYPEPROTO_SLOTS
378 };
379
380 enum CTypeSlot {
381   SLOT_PROTO     = 0, // 'prototype' property of the CType object
382   SLOT_TYPECODE  = 1, // TypeCode of the CType object
383   SLOT_FFITYPE   = 2, // ffi_type representing the type
384   SLOT_NAME      = 3, // name of the type
385   SLOT_SIZE      = 4, // size of the type, in bytes
386   SLOT_ALIGN     = 5, // alignment of the type, in bytes
387   SLOT_PTR       = 6, // cached PointerType object for type.ptr
388   // Note that some of the slots below can overlap, since they're for
389   // mutually exclusive types.
390   SLOT_TARGET_T  = 7, // (PointerTypes only) 'targetType' property
391   SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property
392   SLOT_LENGTH    = 8, // (ArrayTypes only) 'length' property
393   SLOT_FIELDS    = 7, // (StructTypes only) 'fields' property
394   SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table
395   SLOT_FNINFO    = 7, // (FunctionTypes only) FunctionInfo struct
396   SLOT_ARGS_T    = 8, // (FunctionTypes only) 'argTypes' property (cached)
397   CTYPE_SLOTS
398 };
399
400 enum CDataSlot {
401   SLOT_CTYPE    = 0, // CType object representing the underlying type
402   SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
403   SLOT_DATA     = 2, // pointer to a buffer containing the binary data
404   SLOT_OWNS     = 3, // JSVAL_TRUE if this CData owns its own buffer
405   CDATA_SLOTS
406 };
407
408 enum CClosureSlot {
409   SLOT_CLOSUREINFO = 0, // ClosureInfo struct
410   CCLOSURE_SLOTS
411 };
412
413 enum TypeCtorSlot {
414   SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
415   // JSFunction objects always get exactly two slots.
416 };
417
418 enum Int64Slot {
419   SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
420   INT64_SLOTS
421 };
422
423 enum Int64FunctionSlot {
424   SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
425   // JSFunction objects always get exactly two slots.
426 };
427
428 /*******************************************************************************
429 ** Object API definitions
430 *******************************************************************************/
431
432 namespace CType {
433   JSObject* Create(JSContext* cx, JSObject* typeProto, JSObject* dataProto,
434     TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType);
435
436   JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName,
437     JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type,
438     jsval size, jsval align, ffi_type* ffiType);
439
440   bool IsCType(JSContext* cx, JSObject* obj);
441   TypeCode GetTypeCode(JSContext* cx, JSObject* typeObj);
442   bool TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2);
443   size_t GetSize(JSContext* cx, JSObject* obj);
444   bool GetSafeSize(JSContext* cx, JSObject* obj, size_t* result);
445   bool IsSizeDefined(JSContext* cx, JSObject* obj);
446   size_t GetAlignment(JSContext* cx, JSObject* obj);
447   ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
448   JSString* GetName(JSContext* cx, JSObject* obj);
449   JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
450   JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
451   JSCTypesCallbacks* GetCallbacksFromType(JSContext* cx, JSObject* obj);
452 }
453
454 namespace PointerType {
455   JSObject* CreateInternal(JSContext* cx, JSObject* baseType);
456
457   JSObject* GetBaseType(JSContext* cx, JSObject* obj);
458 }
459
460 namespace ArrayType {
461   JSObject* CreateInternal(JSContext* cx, JSObject* baseType, size_t length,
462     bool lengthDefined);
463
464   JSObject* GetBaseType(JSContext* cx, JSObject* obj);
465   size_t GetLength(JSContext* cx, JSObject* obj);
466   bool GetSafeLength(JSContext* cx, JSObject* obj, size_t* result);
467   ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
468 }
469
470 namespace StructType {
471   JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
472
473   const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
474   const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
475   JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
476   ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
477 }
478
479 namespace FunctionType {
480   JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype,
481     jsval* argtypes, jsuint arglen);
482
483   JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
484     JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
485
486   FunctionInfo* GetFunctionInfo(JSContext* cx, JSObject* obj);
487   JSObject* GetLibrary(JSContext* cx, JSObject* obj);
488   void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
489     AutoCString& result);
490 }
491
492 namespace CClosure {
493   JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* fnObj,
494     JSObject* thisObj, PRFuncPtr* fnptr);
495 }
496
497 namespace CData {
498   JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* refObj,
499     void* data, bool ownResult);
500
501   JSObject* GetCType(JSContext* cx, JSObject* dataObj);
502   void* GetData(JSContext* cx, JSObject* dataObj);
503   bool IsCData(JSContext* cx, JSObject* obj);
504
505   // Attached by JSAPI as the function 'ctypes.cast'
506   JSBool Cast(JSContext* cx, uintN argc, jsval* vp);
507 }
508
509 namespace Int64 {
510   bool IsInt64(JSContext* cx, JSObject* obj);
511 }
512
513 namespace UInt64 {
514   bool IsUInt64(JSContext* cx, JSObject* obj);
515 }
516
517 }
518 }
519
520 #endif