summaryrefslogtreecommitdiff
path: root/js/src/ctypes/CTypes.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/ctypes/CTypes.h')
-rw-r--r--js/src/ctypes/CTypes.h520
1 files changed, 520 insertions, 0 deletions
diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h
new file mode 100644
index 0000000..a5942e0
--- /dev/null
+++ b/js/src/ctypes/CTypes.h
@@ -0,0 +1,520 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is js-ctypes.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dan Witte <dwitte@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef CTYPES_H
+#define CTYPES_H
+
+#include "jscntxt.h"
+#include "jsapi.h"
+#include "jshashtable.h"
+#include "prlink.h"
+#include "ffi.h"
+
+namespace js {
+namespace ctypes {
+
+/*******************************************************************************
+** Utility classes
+*******************************************************************************/
+
+template<class T>
+class OperatorDelete
+{
+public:
+ static void destroy(T* ptr) { js_delete(ptr); }
+};
+
+template<class T>
+class OperatorArrayDelete
+{
+public:
+ static void destroy(T* ptr) { js_array_delete(ptr); }
+};
+
+// Class that takes ownership of a pointer T*, and calls js_delete() or
+// js_array_delete() upon destruction.
+template<class T, class DeleteTraits = OperatorDelete<T> >
+class AutoPtr {
+private:
+ typedef AutoPtr<T, DeleteTraits> self_type;
+
+public:
+ // An AutoPtr variant that calls js_array_delete() instead.
+ typedef AutoPtr<T, OperatorArrayDelete<T> > Array;
+
+ AutoPtr() : mPtr(NULL) { }
+ explicit AutoPtr(T* ptr) : mPtr(ptr) { }
+ ~AutoPtr() { DeleteTraits::destroy(mPtr); }
+
+ T* operator->() { return mPtr; }
+ bool operator!() { return mPtr == NULL; }
+ T& operator[](size_t i) { return *(mPtr + i); }
+ // Note: we cannot safely provide an 'operator T*()', since this would allow
+ // the compiler to perform implicit conversion from one AutoPtr to another
+ // via the constructor AutoPtr(T*).
+
+ T* get() { return mPtr; }
+ void set(T* other) { JS_ASSERT(mPtr == NULL); mPtr = other; }
+ T* forget() { T* result = mPtr; mPtr = NULL; return result; }
+
+ self_type& operator=(T* rhs) { mPtr = rhs; return *this; }
+
+private:
+ // Do not allow copy construction or assignment from another AutoPtr.
+ template<class U> AutoPtr(AutoPtr<T, U>&);
+ template<class U> self_type& operator=(AutoPtr<T, U>& rhs);
+
+ T* mPtr;
+};
+
+// Container class for Vector, using SystemAllocPolicy.
+template<class T, size_t N = 0>
+class Array : public Vector<T, N, SystemAllocPolicy>
+{
+};
+
+// String and AutoString classes, based on Vector.
+typedef Vector<jschar, 0, SystemAllocPolicy> String;
+typedef Vector<jschar, 64, SystemAllocPolicy> AutoString;
+typedef Vector<char, 0, SystemAllocPolicy> CString;
+typedef Vector<char, 64, SystemAllocPolicy> AutoCString;
+
+// Convenience functions to append, insert, and compare Strings.
+template <class T, size_t N, class AP, size_t ArrayLength>
+void
+AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
+{
+ // Don't include the trailing '\0'.
+ size_t alen = ArrayLength - 1;
+ size_t vlen = v.length();
+ if (!v.resize(vlen + alen))
+ return;
+
+ for (size_t i = 0; i < alen; ++i)
+ v[i + vlen] = array[i];
+}
+
+template <class T, size_t N, size_t M, class AP>
+void
+AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
+{
+ v.append(w.begin(), w.length());
+}
+
+template <size_t N, class AP>
+void
+AppendString(Vector<jschar, N, AP> &v, JSString* str)
+{
+ JS_ASSERT(str);
+ const jschar *chars = str->getChars(NULL);
+ if (!chars)
+ return;
+ v.append(chars, str->length());
+}
+
+template <size_t N, class AP>
+void
+AppendString(Vector<char, N, AP> &v, JSString* str)
+{
+ JS_ASSERT(str);
+ size_t vlen = v.length();
+ size_t alen = str->length();
+ if (!v.resize(vlen + alen))
+ return;
+
+ const jschar *chars = str->getChars(NULL);
+ if (!chars)
+ return;
+
+ for (size_t i = 0; i < alen; ++i)
+ v[i + vlen] = char(chars[i]);
+}
+
+template <class T, size_t N, class AP, size_t ArrayLength>
+void
+PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
+{
+ // Don't include the trailing '\0'.
+ size_t alen = ArrayLength - 1;
+ size_t vlen = v.length();
+ if (!v.resize(vlen + alen))
+ return;
+
+ // Move vector data forward. This is safe since we've already resized.
+ memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
+
+ // Copy data to insert.
+ for (size_t i = 0; i < alen; ++i)
+ v[i] = array[i];
+}
+
+template <size_t N, class AP>
+void
+PrependString(Vector<jschar, N, AP> &v, JSString* str)
+{
+ JS_ASSERT(str);
+ size_t vlen = v.length();
+ size_t alen = str->length();
+ if (!v.resize(vlen + alen))
+ return;
+
+ const jschar *chars = str->getChars(NULL);
+ if (!chars)
+ return;
+
+ // Move vector data forward. This is safe since we've already resized.
+ memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
+
+ // Copy data to insert.
+ memcpy(v.begin(), chars, alen * sizeof(jschar));
+}
+
+/*******************************************************************************
+** Function and struct API definitions
+*******************************************************************************/
+
+JS_ALWAYS_INLINE void
+ASSERT_OK(JSBool ok)
+{
+ JS_ASSERT(ok);
+}
+
+// for JS error reporting
+enum ErrorNum {
+#define MSG_DEF(name, number, count, exception, format) \
+ name = number,
+#include "ctypes.msg"
+#undef MSG_DEF
+ CTYPESERR_LIMIT
+};
+
+const JSErrorFormatString*
+GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
+JSBool TypeError(JSContext* cx, const char* expected, jsval actual);
+
+/**
+ * ABI constants that specify the calling convention to use.
+ * ctypes.default_abi corresponds to the cdecl convention, and in almost all
+ * cases is the correct choice. ctypes.stdcall_abi is provided for calling
+ * stdcall functions on Win32, and implies stdcall symbol name decoration;
+ * ctypes.winapi_abi is just stdcall but without decoration.
+ */
+enum ABICode {
+ ABI_DEFAULT,
+ ABI_STDCALL,
+ ABI_WINAPI,
+ INVALID_ABI
+};
+
+enum TypeCode {
+ TYPE_void_t,
+#define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
+#include "typedefs.h"
+ TYPE_pointer,
+ TYPE_function,
+ TYPE_array,
+ TYPE_struct
+};
+
+// Descriptor of one field in a StructType. The name of the field is stored
+// as the key to the hash entry.
+struct FieldInfo
+{
+ JSObject* mType; // CType of the field
+ size_t mIndex; // index of the field in the struct (first is 0)
+ size_t mOffset; // offset of the field in the struct, in bytes
+};
+
+// Hash policy for FieldInfos.
+struct FieldHashPolicy
+{
+ typedef JSFlatString* Key;
+ typedef Key Lookup;
+
+ static uint32 hash(const Lookup &l) {
+ const jschar* s = l->chars();
+ size_t n = l->length();
+ uint32 hash = 0;
+ for (; n > 0; s++, n--)
+ hash = hash * 33 + *s;
+ return hash;
+ }
+
+ static JSBool match(const Key &k, const Lookup &l) {
+ if (k == l)
+ return true;
+
+ if (k->length() != l->length())
+ return false;
+
+ return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
+ }
+};
+
+typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
+
+// Descriptor of ABI, return type, argument types, and variadicity for a
+// FunctionType.
+struct FunctionInfo
+{
+ // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
+ // FunctionType::Call, when mIsVariadic. Not always consistent with
+ // mFFITypes, due to lazy initialization when mIsVariadic.
+ ffi_cif mCIF;
+
+ // Calling convention of the function. Convert to ffi_abi using GetABI
+ // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing.
+ JSObject* mABI;
+
+ // The CType of the value returned by the function.
+ JSObject* mReturnType;
+
+ // A fixed array of known parameter types, excluding any variadic
+ // parameters (if mIsVariadic).
+ Array<JSObject*> mArgTypes;
+
+ // A variable array of ffi_type*s corresponding to both known parameter
+ // types and dynamic (variadic) parameter types. Longer than mArgTypes
+ // only if mIsVariadic.
+ Array<ffi_type*> mFFITypes;
+
+ // Flag indicating whether the function behaves like a C function with
+ // ... as the final formal parameter.
+ bool mIsVariadic;
+};
+
+// Parameters necessary for invoking a JS function from a C closure.
+struct ClosureInfo
+{
+ JSContext* cx; // JSContext to use
+ JSObject* closureObj; // CClosure object
+ JSObject* typeObj; // FunctionType describing the C function
+ JSObject* thisObj; // 'this' object to use for the JS function call
+ JSObject* jsfnObj; // JS function
+ ffi_closure* closure; // The C closure itself
+#ifdef DEBUG
+ jsword cxThread; // The thread on which the context may be used
+#endif
+};
+
+bool IsCTypesGlobal(JSContext* cx, JSObject* obj);
+
+JSCTypesCallbacks* GetCallbacks(JSContext* cx, JSObject* obj);
+
+JSBool InitTypeClasses(JSContext* cx, JSObject* parent);
+
+JSBool ConvertToJS(JSContext* cx, JSObject* typeObj, JSObject* dataObj,
+ void* data, bool wantPrimitive, bool ownResult, jsval* result);
+
+JSBool ImplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
+ void* buffer, bool isArgument, bool* freePointer);
+
+JSBool ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType,
+ void* buffer);
+
+/*******************************************************************************
+** JSClass reserved slot definitions
+*******************************************************************************/
+
+enum CTypesGlobalSlot {
+ SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct
+ CTYPESGLOBAL_SLOTS
+};
+
+enum CABISlot {
+ SLOT_ABICODE = 0, // ABICode of the CABI object
+ CABI_SLOTS
+};
+
+enum CTypeProtoSlot {
+ SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object
+ SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object
+ SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object
+ SLOT_FUNCTIONPROTO = 3, // ctypes.FunctionType.prototype object
+ SLOT_CDATAPROTO = 4, // ctypes.CData.prototype object
+ SLOT_POINTERDATAPROTO = 5, // common ancestor of all CData objects of PointerType
+ SLOT_ARRAYDATAPROTO = 6, // common ancestor of all CData objects of ArrayType
+ SLOT_STRUCTDATAPROTO = 7, // common ancestor of all CData objects of StructType
+ SLOT_FUNCTIONDATAPROTO = 8, // common ancestor of all CData objects of FunctionType
+ SLOT_INT64PROTO = 9, // ctypes.Int64.prototype object
+ SLOT_UINT64PROTO = 10, // ctypes.UInt64.prototype object
+ SLOT_CLOSURECX = 11, // JSContext for use with FunctionType closures
+ CTYPEPROTO_SLOTS
+};
+
+enum CTypeSlot {
+ SLOT_PROTO = 0, // 'prototype' property of the CType object
+ SLOT_TYPECODE = 1, // TypeCode of the CType object
+ SLOT_FFITYPE = 2, // ffi_type representing the type
+ SLOT_NAME = 3, // name of the type
+ SLOT_SIZE = 4, // size of the type, in bytes
+ SLOT_ALIGN = 5, // alignment of the type, in bytes
+ SLOT_PTR = 6, // cached PointerType object for type.ptr
+ // Note that some of the slots below can overlap, since they're for
+ // mutually exclusive types.
+ SLOT_TARGET_T = 7, // (PointerTypes only) 'targetType' property
+ SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property
+ SLOT_LENGTH = 8, // (ArrayTypes only) 'length' property
+ SLOT_FIELDS = 7, // (StructTypes only) 'fields' property
+ SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table
+ SLOT_FNINFO = 7, // (FunctionTypes only) FunctionInfo struct
+ SLOT_ARGS_T = 8, // (FunctionTypes only) 'argTypes' property (cached)
+ CTYPE_SLOTS
+};
+
+enum CDataSlot {
+ SLOT_CTYPE = 0, // CType object representing the underlying type
+ SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
+ SLOT_DATA = 2, // pointer to a buffer containing the binary data
+ SLOT_OWNS = 3, // JSVAL_TRUE if this CData owns its own buffer
+ CDATA_SLOTS
+};
+
+enum CClosureSlot {
+ SLOT_CLOSUREINFO = 0, // ClosureInfo struct
+ CCLOSURE_SLOTS
+};
+
+enum TypeCtorSlot {
+ SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
+ // JSFunction objects always get exactly two slots.
+};
+
+enum Int64Slot {
+ SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
+ INT64_SLOTS
+};
+
+enum Int64FunctionSlot {
+ SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
+ // JSFunction objects always get exactly two slots.
+};
+
+/*******************************************************************************
+** Object API definitions
+*******************************************************************************/
+
+namespace CType {
+ JSObject* Create(JSContext* cx, JSObject* typeProto, JSObject* dataProto,
+ TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType);
+
+ JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName,
+ JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type,
+ jsval size, jsval align, ffi_type* ffiType);
+
+ bool IsCType(JSContext* cx, JSObject* obj);
+ TypeCode GetTypeCode(JSContext* cx, JSObject* typeObj);
+ bool TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2);
+ size_t GetSize(JSContext* cx, JSObject* obj);
+ bool GetSafeSize(JSContext* cx, JSObject* obj, size_t* result);
+ bool IsSizeDefined(JSContext* cx, JSObject* obj);
+ size_t GetAlignment(JSContext* cx, JSObject* obj);
+ ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
+ JSString* GetName(JSContext* cx, JSObject* obj);
+ JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
+ JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
+ JSCTypesCallbacks* GetCallbacksFromType(JSContext* cx, JSObject* obj);
+}
+
+namespace PointerType {
+ JSObject* CreateInternal(JSContext* cx, JSObject* baseType);
+
+ JSObject* GetBaseType(JSContext* cx, JSObject* obj);
+}
+
+namespace ArrayType {
+ JSObject* CreateInternal(JSContext* cx, JSObject* baseType, size_t length,
+ bool lengthDefined);
+
+ JSObject* GetBaseType(JSContext* cx, JSObject* obj);
+ size_t GetLength(JSContext* cx, JSObject* obj);
+ bool GetSafeLength(JSContext* cx, JSObject* obj, size_t* result);
+ ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
+}
+
+namespace StructType {
+ JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
+
+ const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
+ const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
+ JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
+ ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
+}
+
+namespace FunctionType {
+ JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype,
+ jsval* argtypes, jsuint arglen);
+
+ JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
+ JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
+
+ FunctionInfo* GetFunctionInfo(JSContext* cx, JSObject* obj);
+ JSObject* GetLibrary(JSContext* cx, JSObject* obj);
+ void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
+ AutoCString& result);
+}
+
+namespace CClosure {
+ JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* fnObj,
+ JSObject* thisObj, PRFuncPtr* fnptr);
+}
+
+namespace CData {
+ JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* refObj,
+ void* data, bool ownResult);
+
+ JSObject* GetCType(JSContext* cx, JSObject* dataObj);
+ void* GetData(JSContext* cx, JSObject* dataObj);
+ bool IsCData(JSContext* cx, JSObject* obj);
+
+ // Attached by JSAPI as the function 'ctypes.cast'
+ JSBool Cast(JSContext* cx, uintN argc, jsval* vp);
+}
+
+namespace Int64 {
+ bool IsInt64(JSContext* cx, JSObject* obj);
+}
+
+namespace UInt64 {
+ bool IsUInt64(JSContext* cx, JSObject* obj);
+}
+
+}
+}
+
+#endif