diff options
Diffstat (limited to 'js/src/ctypes/CTypes.h')
-rw-r--r-- | js/src/ctypes/CTypes.h | 520 |
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 |