1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/ctypes/CTypes.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,509 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef ctypes_CTypes_h 1.10 +#define ctypes_CTypes_h 1.11 + 1.12 +#include "ffi.h" 1.13 +#include "jsalloc.h" 1.14 +#include "prlink.h" 1.15 + 1.16 +#include "js/HashTable.h" 1.17 +#include "js/Vector.h" 1.18 +#include "vm/String.h" 1.19 + 1.20 +namespace js { 1.21 +namespace ctypes { 1.22 + 1.23 +/******************************************************************************* 1.24 +** Utility classes 1.25 +*******************************************************************************/ 1.26 + 1.27 +// Class that takes ownership of a pointer T*, and calls cx->delete_() or 1.28 +// cx->array_delete() upon destruction. 1.29 +template<class T> 1.30 +class AutoPtr { 1.31 +private: 1.32 + typedef AutoPtr<T> self_type; 1.33 + 1.34 +public: 1.35 + AutoPtr() : mPtr(nullptr) { } 1.36 + explicit AutoPtr(T* ptr) : mPtr(ptr) { } 1.37 + ~AutoPtr() { js_delete(mPtr); } 1.38 + 1.39 + T* operator->() { return mPtr; } 1.40 + bool operator!() { return mPtr == nullptr; } 1.41 + T& operator[](size_t i) { return *(mPtr + i); } 1.42 + // Note: we cannot safely provide an 'operator T*()', since this would allow 1.43 + // the compiler to perform implicit conversion from one AutoPtr to another 1.44 + // via the constructor AutoPtr(T*). 1.45 + 1.46 + T* get() { return mPtr; } 1.47 + void set(T* other) { JS_ASSERT(mPtr == nullptr); mPtr = other; } 1.48 + T* forget() { T* result = mPtr; mPtr = nullptr; return result; } 1.49 + 1.50 + self_type& operator=(T* rhs) { mPtr = rhs; return *this; } 1.51 + 1.52 +private: 1.53 + // Do not allow copy construction or assignment from another AutoPtr. 1.54 + AutoPtr(AutoPtr<T>&); 1.55 + self_type& operator=(AutoPtr<T>& rhs); 1.56 + 1.57 + T* mPtr; 1.58 +}; 1.59 + 1.60 +// Container class for Vector, using SystemAllocPolicy. 1.61 +template<class T, size_t N = 0> 1.62 +class Array : public Vector<T, N, SystemAllocPolicy> 1.63 +{ 1.64 + static_assert(!mozilla::IsSame<T, JS::Value>::value, 1.65 + "use JS::AutoValueVector instead"); 1.66 +}; 1.67 + 1.68 +// String and AutoString classes, based on Vector. 1.69 +typedef Vector<jschar, 0, SystemAllocPolicy> String; 1.70 +typedef Vector<jschar, 64, SystemAllocPolicy> AutoString; 1.71 +typedef Vector<char, 0, SystemAllocPolicy> CString; 1.72 +typedef Vector<char, 64, SystemAllocPolicy> AutoCString; 1.73 + 1.74 +// Convenience functions to append, insert, and compare Strings. 1.75 +template <class T, size_t N, class AP, size_t ArrayLength> 1.76 +void 1.77 +AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength]) 1.78 +{ 1.79 + // Don't include the trailing '\0'. 1.80 + size_t alen = ArrayLength - 1; 1.81 + size_t vlen = v.length(); 1.82 + if (!v.resize(vlen + alen)) 1.83 + return; 1.84 + 1.85 + for (size_t i = 0; i < alen; ++i) 1.86 + v[i + vlen] = array[i]; 1.87 +} 1.88 + 1.89 +template <class T, size_t N, size_t M, class AP> 1.90 +void 1.91 +AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w) 1.92 +{ 1.93 + v.append(w.begin(), w.length()); 1.94 +} 1.95 + 1.96 +template <size_t N, class AP> 1.97 +void 1.98 +AppendString(Vector<jschar, N, AP> &v, JSString* str) 1.99 +{ 1.100 + JS_ASSERT(str); 1.101 + const jschar *chars = str->getChars(nullptr); 1.102 + if (!chars) 1.103 + return; 1.104 + v.append(chars, str->length()); 1.105 +} 1.106 + 1.107 +template <size_t N, class AP> 1.108 +void 1.109 +AppendString(Vector<char, N, AP> &v, JSString* str) 1.110 +{ 1.111 + JS_ASSERT(str); 1.112 + size_t vlen = v.length(); 1.113 + size_t alen = str->length(); 1.114 + if (!v.resize(vlen + alen)) 1.115 + return; 1.116 + 1.117 + const jschar *chars = str->getChars(nullptr); 1.118 + if (!chars) 1.119 + return; 1.120 + 1.121 + for (size_t i = 0; i < alen; ++i) 1.122 + v[i + vlen] = char(chars[i]); 1.123 +} 1.124 + 1.125 +template <class T, size_t N, class AP, size_t ArrayLength> 1.126 +void 1.127 +PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength]) 1.128 +{ 1.129 + // Don't include the trailing '\0'. 1.130 + size_t alen = ArrayLength - 1; 1.131 + size_t vlen = v.length(); 1.132 + if (!v.resize(vlen + alen)) 1.133 + return; 1.134 + 1.135 + // Move vector data forward. This is safe since we've already resized. 1.136 + memmove(v.begin() + alen, v.begin(), vlen * sizeof(T)); 1.137 + 1.138 + // Copy data to insert. 1.139 + for (size_t i = 0; i < alen; ++i) 1.140 + v[i] = array[i]; 1.141 +} 1.142 + 1.143 +template <size_t N, class AP> 1.144 +void 1.145 +PrependString(Vector<jschar, N, AP> &v, JSString* str) 1.146 +{ 1.147 + JS_ASSERT(str); 1.148 + size_t vlen = v.length(); 1.149 + size_t alen = str->length(); 1.150 + if (!v.resize(vlen + alen)) 1.151 + return; 1.152 + 1.153 + const jschar *chars = str->getChars(nullptr); 1.154 + if (!chars) 1.155 + return; 1.156 + 1.157 + // Move vector data forward. This is safe since we've already resized. 1.158 + memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar)); 1.159 + 1.160 + // Copy data to insert. 1.161 + memcpy(v.begin(), chars, alen * sizeof(jschar)); 1.162 +} 1.163 + 1.164 +extern size_t 1.165 +GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars, 1.166 + size_t charsLength); 1.167 + 1.168 +bool 1.169 +DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen, 1.170 + char *dst, size_t *dstlenp); 1.171 + 1.172 + 1.173 +/******************************************************************************* 1.174 +** Function and struct API definitions 1.175 +*******************************************************************************/ 1.176 + 1.177 +MOZ_ALWAYS_INLINE void 1.178 +ASSERT_OK(bool ok) 1.179 +{ 1.180 + JS_ASSERT(ok); 1.181 +} 1.182 + 1.183 +// for JS error reporting 1.184 +enum ErrorNum { 1.185 +#define MSG_DEF(name, number, count, exception, format) \ 1.186 + name = number, 1.187 +#include "ctypes/ctypes.msg" 1.188 +#undef MSG_DEF 1.189 + CTYPESERR_LIMIT 1.190 +}; 1.191 + 1.192 +/** 1.193 + * ABI constants that specify the calling convention to use. 1.194 + * ctypes.default_abi corresponds to the cdecl convention, and in almost all 1.195 + * cases is the correct choice. ctypes.stdcall_abi is provided for calling 1.196 + * stdcall functions on Win32, and implies stdcall symbol name decoration; 1.197 + * ctypes.winapi_abi is just stdcall but without decoration. 1.198 + */ 1.199 +enum ABICode { 1.200 + ABI_DEFAULT, 1.201 + ABI_STDCALL, 1.202 + ABI_WINAPI, 1.203 + INVALID_ABI 1.204 +}; 1.205 + 1.206 +enum TypeCode { 1.207 + TYPE_void_t, 1.208 +#define DEFINE_TYPE(name, type, ffiType) TYPE_##name, 1.209 +#include "ctypes/typedefs.h" 1.210 + TYPE_pointer, 1.211 + TYPE_function, 1.212 + TYPE_array, 1.213 + TYPE_struct 1.214 +}; 1.215 + 1.216 +// Descriptor of one field in a StructType. The name of the field is stored 1.217 +// as the key to the hash entry. 1.218 +struct FieldInfo 1.219 +{ 1.220 + JS::Heap<JSObject*> mType; // CType of the field 1.221 + size_t mIndex; // index of the field in the struct (first is 0) 1.222 + size_t mOffset; // offset of the field in the struct, in bytes 1.223 +}; 1.224 + 1.225 +struct UnbarrieredFieldInfo 1.226 +{ 1.227 + JSObject* mType; // CType of the field 1.228 + size_t mIndex; // index of the field in the struct (first is 0) 1.229 + size_t mOffset; // offset of the field in the struct, in bytes 1.230 +}; 1.231 +static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo), 1.232 + "UnbarrieredFieldInfo should be the same as FieldInfo but with unbarriered mType"); 1.233 + 1.234 +// Hash policy for FieldInfos. 1.235 +struct FieldHashPolicy : DefaultHasher<JSFlatString*> 1.236 +{ 1.237 + typedef JSFlatString* Key; 1.238 + typedef Key Lookup; 1.239 + 1.240 + static uint32_t hash(const Lookup &l) { 1.241 + const jschar* s = l->chars(); 1.242 + size_t n = l->length(); 1.243 + uint32_t hash = 0; 1.244 + for (; n > 0; s++, n--) 1.245 + hash = hash * 33 + *s; 1.246 + return hash; 1.247 + } 1.248 + 1.249 + static bool match(const Key &k, const Lookup &l) { 1.250 + if (k == l) 1.251 + return true; 1.252 + 1.253 + if (k->length() != l->length()) 1.254 + return false; 1.255 + 1.256 + return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0; 1.257 + } 1.258 +}; 1.259 + 1.260 +typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash; 1.261 + 1.262 +// Descriptor of ABI, return type, argument types, and variadicity for a 1.263 +// FunctionType. 1.264 +struct FunctionInfo 1.265 +{ 1.266 + // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in 1.267 + // FunctionType::Call, when mIsVariadic. Not always consistent with 1.268 + // mFFITypes, due to lazy initialization when mIsVariadic. 1.269 + ffi_cif mCIF; 1.270 + 1.271 + // Calling convention of the function. Convert to ffi_abi using GetABI 1.272 + // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing. 1.273 + JS::Heap<JSObject*> mABI; 1.274 + 1.275 + // The CType of the value returned by the function. 1.276 + JS::Heap<JSObject*> mReturnType; 1.277 + 1.278 + // A fixed array of known parameter types, excluding any variadic 1.279 + // parameters (if mIsVariadic). 1.280 + Array<JS::Heap<JSObject*> > mArgTypes; 1.281 + 1.282 + // A variable array of ffi_type*s corresponding to both known parameter 1.283 + // types and dynamic (variadic) parameter types. Longer than mArgTypes 1.284 + // only if mIsVariadic. 1.285 + Array<ffi_type*> mFFITypes; 1.286 + 1.287 + // Flag indicating whether the function behaves like a C function with 1.288 + // ... as the final formal parameter. 1.289 + bool mIsVariadic; 1.290 +}; 1.291 + 1.292 +// Parameters necessary for invoking a JS function from a C closure. 1.293 +struct ClosureInfo 1.294 +{ 1.295 + JSContext* cx; // JSContext to use 1.296 + JSRuntime* rt; // Used in the destructor, where cx might have already 1.297 + // been GCed. 1.298 + JS::Heap<JSObject*> closureObj; // CClosure object 1.299 + JS::Heap<JSObject*> typeObj; // FunctionType describing the C function 1.300 + JS::Heap<JSObject*> thisObj; // 'this' object to use for the JS function call 1.301 + JS::Heap<JSObject*> jsfnObj; // JS function 1.302 + void* errResult; // Result that will be returned if the closure throws 1.303 + ffi_closure* closure; // The C closure itself 1.304 + 1.305 + // Anything conditionally freed in the destructor should be initialized to 1.306 + // nullptr here. 1.307 + ClosureInfo(JSRuntime* runtime) 1.308 + : rt(runtime) 1.309 + , errResult(nullptr) 1.310 + , closure(nullptr) 1.311 + {} 1.312 + 1.313 + ~ClosureInfo() { 1.314 + if (closure) 1.315 + ffi_closure_free(closure); 1.316 + js_free(errResult); 1.317 + } 1.318 +}; 1.319 + 1.320 +bool IsCTypesGlobal(HandleValue v); 1.321 +bool IsCTypesGlobal(JSObject* obj); 1.322 + 1.323 +JSCTypesCallbacks* GetCallbacks(JSObject* obj); 1.324 + 1.325 +/******************************************************************************* 1.326 +** JSClass reserved slot definitions 1.327 +*******************************************************************************/ 1.328 + 1.329 +enum CTypesGlobalSlot { 1.330 + SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct 1.331 + SLOT_ERRNO = 1, // jsval for latest |errno| 1.332 + SLOT_LASTERROR = 2, // jsval for latest |GetLastError|, used only with Windows 1.333 + CTYPESGLOBAL_SLOTS 1.334 +}; 1.335 + 1.336 +enum CABISlot { 1.337 + SLOT_ABICODE = 0, // ABICode of the CABI object 1.338 + CABI_SLOTS 1.339 +}; 1.340 + 1.341 +enum CTypeProtoSlot { 1.342 + SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object 1.343 + SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object 1.344 + SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object 1.345 + SLOT_FUNCTIONPROTO = 3, // ctypes.FunctionType.prototype object 1.346 + SLOT_CDATAPROTO = 4, // ctypes.CData.prototype object 1.347 + SLOT_POINTERDATAPROTO = 5, // common ancestor of all CData objects of PointerType 1.348 + SLOT_ARRAYDATAPROTO = 6, // common ancestor of all CData objects of ArrayType 1.349 + SLOT_STRUCTDATAPROTO = 7, // common ancestor of all CData objects of StructType 1.350 + SLOT_FUNCTIONDATAPROTO = 8, // common ancestor of all CData objects of FunctionType 1.351 + SLOT_INT64PROTO = 9, // ctypes.Int64.prototype object 1.352 + SLOT_UINT64PROTO = 10, // ctypes.UInt64.prototype object 1.353 + SLOT_CTYPES = 11, // ctypes object 1.354 + SLOT_OURDATAPROTO = 12, // the data prototype corresponding to this object 1.355 + CTYPEPROTO_SLOTS 1.356 +}; 1.357 + 1.358 +enum CTypeSlot { 1.359 + SLOT_PROTO = 0, // 'prototype' property of the CType object 1.360 + SLOT_TYPECODE = 1, // TypeCode of the CType object 1.361 + SLOT_FFITYPE = 2, // ffi_type representing the type 1.362 + SLOT_NAME = 3, // name of the type 1.363 + SLOT_SIZE = 4, // size of the type, in bytes 1.364 + SLOT_ALIGN = 5, // alignment of the type, in bytes 1.365 + SLOT_PTR = 6, // cached PointerType object for type.ptr 1.366 + // Note that some of the slots below can overlap, since they're for 1.367 + // mutually exclusive types. 1.368 + SLOT_TARGET_T = 7, // (PointerTypes only) 'targetType' property 1.369 + SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property 1.370 + SLOT_LENGTH = 8, // (ArrayTypes only) 'length' property 1.371 + SLOT_FIELDS = 7, // (StructTypes only) 'fields' property 1.372 + SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table 1.373 + SLOT_FNINFO = 7, // (FunctionTypes only) FunctionInfo struct 1.374 + SLOT_ARGS_T = 8, // (FunctionTypes only) 'argTypes' property (cached) 1.375 + CTYPE_SLOTS 1.376 +}; 1.377 + 1.378 +enum CDataSlot { 1.379 + SLOT_CTYPE = 0, // CType object representing the underlying type 1.380 + SLOT_REFERENT = 1, // JSObject this object must keep alive, if any 1.381 + SLOT_DATA = 2, // pointer to a buffer containing the binary data 1.382 + SLOT_OWNS = 3, // JSVAL_TRUE if this CData owns its own buffer 1.383 + CDATA_SLOTS 1.384 +}; 1.385 + 1.386 +enum CClosureSlot { 1.387 + SLOT_CLOSUREINFO = 0, // ClosureInfo struct 1.388 + CCLOSURE_SLOTS 1.389 +}; 1.390 + 1.391 +enum CDataFinalizerSlot { 1.392 + // The type of the value (a CType JSObject). 1.393 + // We hold it to permit ImplicitConvert and ToSource. 1.394 + SLOT_DATAFINALIZER_VALTYPE = 0, 1.395 + // The type of the function used at finalization (a CType JSObject). 1.396 + // We hold it to permit |ToSource|. 1.397 + SLOT_DATAFINALIZER_CODETYPE = 1, 1.398 + CDATAFINALIZER_SLOTS 1.399 +}; 1.400 + 1.401 +enum TypeCtorSlot { 1.402 + SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype 1.403 + // JSFunction objects always get exactly two slots. 1.404 +}; 1.405 + 1.406 +enum Int64Slot { 1.407 + SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer 1.408 + INT64_SLOTS 1.409 +}; 1.410 + 1.411 +enum Int64FunctionSlot { 1.412 + SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object 1.413 + // JSFunction objects always get exactly two slots. 1.414 +}; 1.415 + 1.416 +/******************************************************************************* 1.417 +** Object API definitions 1.418 +*******************************************************************************/ 1.419 + 1.420 +namespace CType { 1.421 + JSObject* Create(JSContext* cx, HandleObject typeProto, HandleObject dataProto, 1.422 + TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType); 1.423 + 1.424 + JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName, 1.425 + JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type, 1.426 + jsval size, jsval align, ffi_type* ffiType); 1.427 + 1.428 + bool IsCType(JSObject* obj); 1.429 + bool IsCTypeProto(JSObject* obj); 1.430 + TypeCode GetTypeCode(JSObject* typeObj); 1.431 + bool TypesEqual(JSObject* t1, JSObject* t2); 1.432 + size_t GetSize(JSObject* obj); 1.433 + bool GetSafeSize(JSObject* obj, size_t* result); 1.434 + bool IsSizeDefined(JSObject* obj); 1.435 + size_t GetAlignment(JSObject* obj); 1.436 + ffi_type* GetFFIType(JSContext* cx, JSObject* obj); 1.437 + JSString* GetName(JSContext* cx, HandleObject obj); 1.438 + JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot); 1.439 + JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); 1.440 + JSCTypesCallbacks* GetCallbacksFromType(JSObject* obj); 1.441 +} 1.442 + 1.443 +namespace PointerType { 1.444 + JSObject* CreateInternal(JSContext* cx, HandleObject baseType); 1.445 + 1.446 + JSObject* GetBaseType(JSObject* obj); 1.447 +} 1.448 + 1.449 +namespace ArrayType { 1.450 + JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length, 1.451 + bool lengthDefined); 1.452 + 1.453 + JSObject* GetBaseType(JSObject* obj); 1.454 + size_t GetLength(JSObject* obj); 1.455 + bool GetSafeLength(JSObject* obj, size_t* result); 1.456 + ffi_type* BuildFFIType(JSContext* cx, JSObject* obj); 1.457 +} 1.458 + 1.459 +namespace StructType { 1.460 + bool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj); 1.461 + 1.462 + const FieldInfoHash* GetFieldInfo(JSObject* obj); 1.463 + const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name); 1.464 + JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj); 1.465 + ffi_type* BuildFFIType(JSContext* cx, JSObject* obj); 1.466 +} 1.467 + 1.468 +namespace FunctionType { 1.469 + JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype, 1.470 + jsval* argtypes, unsigned arglen); 1.471 + 1.472 + JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj, 1.473 + JSObject* refObj, PRFuncPtr fnptr, JSObject* result); 1.474 + 1.475 + FunctionInfo* GetFunctionInfo(JSObject* obj); 1.476 + void BuildSymbolName(JSString* name, JSObject* typeObj, 1.477 + AutoCString& result); 1.478 +} 1.479 + 1.480 +namespace CClosure { 1.481 + JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj, 1.482 + HandleObject thisObj, jsval errVal, PRFuncPtr* fnptr); 1.483 +} 1.484 + 1.485 +namespace CData { 1.486 + JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject refObj, 1.487 + void* data, bool ownResult); 1.488 + 1.489 + JSObject* GetCType(JSObject* dataObj); 1.490 + void* GetData(JSObject* dataObj); 1.491 + bool IsCData(JSObject* obj); 1.492 + bool IsCData(HandleValue v); 1.493 + bool IsCDataProto(JSObject* obj); 1.494 + 1.495 + // Attached by JSAPI as the function 'ctypes.cast' 1.496 + bool Cast(JSContext* cx, unsigned argc, jsval* vp); 1.497 + // Attached by JSAPI as the function 'ctypes.getRuntime' 1.498 + bool GetRuntime(JSContext* cx, unsigned argc, jsval* vp); 1.499 +} 1.500 + 1.501 +namespace Int64 { 1.502 + bool IsInt64(JSObject* obj); 1.503 +} 1.504 + 1.505 +namespace UInt64 { 1.506 + bool IsUInt64(JSObject* obj); 1.507 +} 1.508 + 1.509 +} 1.510 +} 1.511 + 1.512 +#endif /* ctypes_CTypes_h */