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
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/
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
15 * The Original Code is js-ctypes.
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.
23 * Dan Witte <dwitte@mozilla.com>
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.
37 * ***** END LICENSE BLOCK ***** */
44 #include "jshashtable.h"
51 /*******************************************************************************
53 *******************************************************************************/
59 static void destroy(T* ptr) { js_delete(ptr); }
63 class OperatorArrayDelete
66 static void destroy(T* ptr) { js_array_delete(ptr); }
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> >
74 typedef AutoPtr<T, DeleteTraits> self_type;
77 // An AutoPtr variant that calls js_array_delete() instead.
78 typedef AutoPtr<T, OperatorArrayDelete<T> > Array;
80 AutoPtr() : mPtr(NULL) { }
81 explicit AutoPtr(T* ptr) : mPtr(ptr) { }
82 ~AutoPtr() { DeleteTraits::destroy(mPtr); }
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*).
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; }
95 self_type& operator=(T* rhs) { mPtr = rhs; return *this; }
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);
105 // Container class for Vector, using SystemAllocPolicy.
106 template<class T, size_t N = 0>
107 class Array : public Vector<T, N, SystemAllocPolicy>
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;
117 // Convenience functions to append, insert, and compare Strings.
118 template <class T, size_t N, class AP, size_t ArrayLength>
120 AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
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))
128 for (size_t i = 0; i < alen; ++i)
129 v[i + vlen] = array[i];
132 template <class T, size_t N, size_t M, class AP>
134 AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
136 v.append(w.begin(), w.length());
139 template <size_t N, class AP>
141 AppendString(Vector<jschar, N, AP> &v, JSString* str)
144 const jschar *chars = str->getChars(NULL);
147 v.append(chars, str->length());
150 template <size_t N, class AP>
152 AppendString(Vector<char, N, AP> &v, JSString* str)
155 size_t vlen = v.length();
156 size_t alen = str->length();
157 if (!v.resize(vlen + alen))
160 const jschar *chars = str->getChars(NULL);
164 for (size_t i = 0; i < alen; ++i)
165 v[i + vlen] = char(chars[i]);
168 template <class T, size_t N, class AP, size_t ArrayLength>
170 PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
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))
178 // Move vector data forward. This is safe since we've already resized.
179 memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
181 // Copy data to insert.
182 for (size_t i = 0; i < alen; ++i)
186 template <size_t N, class AP>
188 PrependString(Vector<jschar, N, AP> &v, JSString* str)
191 size_t vlen = v.length();
192 size_t alen = str->length();
193 if (!v.resize(vlen + alen))
196 const jschar *chars = str->getChars(NULL);
200 // Move vector data forward. This is safe since we've already resized.
201 memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
203 // Copy data to insert.
204 memcpy(v.begin(), chars, alen * sizeof(jschar));
207 /*******************************************************************************
208 ** Function and struct API definitions
209 *******************************************************************************/
211 JS_ALWAYS_INLINE void
217 // for JS error reporting
219 #define MSG_DEF(name, number, count, exception, format) \
221 #include "ctypes.msg"
226 const JSErrorFormatString*
227 GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
228 JSBool TypeError(JSContext* cx, const char* expected, jsval actual);
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.
246 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
247 #include "typedefs.h"
254 // Descriptor of one field in a StructType. The name of the field is stored
255 // as the key to the hash entry.
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
263 // Hash policy for FieldInfos.
264 struct FieldHashPolicy
266 typedef JSFlatString* Key;
269 static uint32 hash(const Lookup &l) {
270 const jschar* s = l->chars();
271 size_t n = l->length();
273 for (; n > 0; s++, n--)
274 hash = hash * 33 + *s;
278 static JSBool match(const Key &k, const Lookup &l) {
282 if (k->length() != l->length())
285 return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
289 typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
291 // Descriptor of ABI, return type, argument types, and variadicity for a
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.
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.
304 // The CType of the value returned by the function.
305 JSObject* mReturnType;
307 // A fixed array of known parameter types, excluding any variadic
308 // parameters (if mIsVariadic).
309 Array<JSObject*> mArgTypes;
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;
316 // Flag indicating whether the function behaves like a C function with
317 // ... as the final formal parameter.
321 // Parameters necessary for invoking a JS function from a C closure.
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
331 jsword cxThread; // The thread on which the context may be used
335 bool IsCTypesGlobal(JSContext* cx, JSObject* obj);
337 JSCTypesCallbacks* GetCallbacks(JSContext* cx, JSObject* obj);
339 JSBool InitTypeClasses(JSContext* cx, JSObject* parent);
341 JSBool ConvertToJS(JSContext* cx, JSObject* typeObj, JSObject* dataObj,
342 void* data, bool wantPrimitive, bool ownResult, jsval* result);
344 JSBool ImplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
345 void* buffer, bool isArgument, bool* freePointer);
347 JSBool ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
350 /*******************************************************************************
351 ** JSClass reserved slot definitions
352 *******************************************************************************/
354 enum CTypesGlobalSlot {
355 SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct
360 SLOT_ABICODE = 0, // ABICode of the CABI object
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
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)
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
409 SLOT_CLOSUREINFO = 0, // ClosureInfo struct
414 SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
415 // JSFunction objects always get exactly two slots.
419 SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
423 enum Int64FunctionSlot {
424 SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
425 // JSFunction objects always get exactly two slots.
428 /*******************************************************************************
429 ** Object API definitions
430 *******************************************************************************/
433 JSObject* Create(JSContext* cx, JSObject* typeProto, JSObject* dataProto,
434 TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType);
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);
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);
454 namespace PointerType {
455 JSObject* CreateInternal(JSContext* cx, JSObject* baseType);
457 JSObject* GetBaseType(JSContext* cx, JSObject* obj);
460 namespace ArrayType {
461 JSObject* CreateInternal(JSContext* cx, JSObject* baseType, size_t length,
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);
470 namespace StructType {
471 JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
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);
479 namespace FunctionType {
480 JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype,
481 jsval* argtypes, jsuint arglen);
483 JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
484 JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
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);
493 JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* fnObj,
494 JSObject* thisObj, PRFuncPtr* fnptr);
498 JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* refObj,
499 void* data, bool ownResult);
501 JSObject* GetCType(JSContext* cx, JSObject* dataObj);
502 void* GetData(JSContext* cx, JSObject* dataObj);
503 bool IsCData(JSContext* cx, JSObject* obj);
505 // Attached by JSAPI as the function 'ctypes.cast'
506 JSBool Cast(JSContext* cx, uintN argc, jsval* vp);
510 bool IsInt64(JSContext* cx, JSObject* obj);
514 bool IsUInt64(JSContext* cx, JSObject* obj);