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