Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef ctypes_CTypes_h
7 #define ctypes_CTypes_h
9 #include "ffi.h"
10 #include "jsalloc.h"
11 #include "prlink.h"
13 #include "js/HashTable.h"
14 #include "js/Vector.h"
15 #include "vm/String.h"
17 namespace js {
18 namespace ctypes {
20 /*******************************************************************************
21 ** Utility classes
22 *******************************************************************************/
24 // Class that takes ownership of a pointer T*, and calls cx->delete_() or
25 // cx->array_delete() upon destruction.
26 template<class T>
27 class AutoPtr {
28 private:
29 typedef AutoPtr<T> self_type;
31 public:
32 AutoPtr() : mPtr(nullptr) { }
33 explicit AutoPtr(T* ptr) : mPtr(ptr) { }
34 ~AutoPtr() { js_delete(mPtr); }
36 T* operator->() { return mPtr; }
37 bool operator!() { return mPtr == nullptr; }
38 T& operator[](size_t i) { return *(mPtr + i); }
39 // Note: we cannot safely provide an 'operator T*()', since this would allow
40 // the compiler to perform implicit conversion from one AutoPtr to another
41 // via the constructor AutoPtr(T*).
43 T* get() { return mPtr; }
44 void set(T* other) { JS_ASSERT(mPtr == nullptr); mPtr = other; }
45 T* forget() { T* result = mPtr; mPtr = nullptr; return result; }
47 self_type& operator=(T* rhs) { mPtr = rhs; return *this; }
49 private:
50 // Do not allow copy construction or assignment from another AutoPtr.
51 AutoPtr(AutoPtr<T>&);
52 self_type& operator=(AutoPtr<T>& rhs);
54 T* mPtr;
55 };
57 // Container class for Vector, using SystemAllocPolicy.
58 template<class T, size_t N = 0>
59 class Array : public Vector<T, N, SystemAllocPolicy>
60 {
61 static_assert(!mozilla::IsSame<T, JS::Value>::value,
62 "use JS::AutoValueVector instead");
63 };
65 // String and AutoString classes, based on Vector.
66 typedef Vector<jschar, 0, SystemAllocPolicy> String;
67 typedef Vector<jschar, 64, SystemAllocPolicy> AutoString;
68 typedef Vector<char, 0, SystemAllocPolicy> CString;
69 typedef Vector<char, 64, SystemAllocPolicy> AutoCString;
71 // Convenience functions to append, insert, and compare Strings.
72 template <class T, size_t N, class AP, size_t ArrayLength>
73 void
74 AppendString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
75 {
76 // Don't include the trailing '\0'.
77 size_t alen = ArrayLength - 1;
78 size_t vlen = v.length();
79 if (!v.resize(vlen + alen))
80 return;
82 for (size_t i = 0; i < alen; ++i)
83 v[i + vlen] = array[i];
84 }
86 template <class T, size_t N, size_t M, class AP>
87 void
88 AppendString(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
89 {
90 v.append(w.begin(), w.length());
91 }
93 template <size_t N, class AP>
94 void
95 AppendString(Vector<jschar, N, AP> &v, JSString* str)
96 {
97 JS_ASSERT(str);
98 const jschar *chars = str->getChars(nullptr);
99 if (!chars)
100 return;
101 v.append(chars, str->length());
102 }
104 template <size_t N, class AP>
105 void
106 AppendString(Vector<char, N, AP> &v, JSString* str)
107 {
108 JS_ASSERT(str);
109 size_t vlen = v.length();
110 size_t alen = str->length();
111 if (!v.resize(vlen + alen))
112 return;
114 const jschar *chars = str->getChars(nullptr);
115 if (!chars)
116 return;
118 for (size_t i = 0; i < alen; ++i)
119 v[i + vlen] = char(chars[i]);
120 }
122 template <class T, size_t N, class AP, size_t ArrayLength>
123 void
124 PrependString(Vector<T, N, AP> &v, const char (&array)[ArrayLength])
125 {
126 // Don't include the trailing '\0'.
127 size_t alen = ArrayLength - 1;
128 size_t vlen = v.length();
129 if (!v.resize(vlen + alen))
130 return;
132 // Move vector data forward. This is safe since we've already resized.
133 memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
135 // Copy data to insert.
136 for (size_t i = 0; i < alen; ++i)
137 v[i] = array[i];
138 }
140 template <size_t N, class AP>
141 void
142 PrependString(Vector<jschar, N, AP> &v, JSString* str)
143 {
144 JS_ASSERT(str);
145 size_t vlen = v.length();
146 size_t alen = str->length();
147 if (!v.resize(vlen + alen))
148 return;
150 const jschar *chars = str->getChars(nullptr);
151 if (!chars)
152 return;
154 // Move vector data forward. This is safe since we've already resized.
155 memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
157 // Copy data to insert.
158 memcpy(v.begin(), chars, alen * sizeof(jschar));
159 }
161 extern size_t
162 GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
163 size_t charsLength);
165 bool
166 DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
167 char *dst, size_t *dstlenp);
170 /*******************************************************************************
171 ** Function and struct API definitions
172 *******************************************************************************/
174 MOZ_ALWAYS_INLINE void
175 ASSERT_OK(bool ok)
176 {
177 JS_ASSERT(ok);
178 }
180 // for JS error reporting
181 enum ErrorNum {
182 #define MSG_DEF(name, number, count, exception, format) \
183 name = number,
184 #include "ctypes/ctypes.msg"
185 #undef MSG_DEF
186 CTYPESERR_LIMIT
187 };
189 /**
190 * ABI constants that specify the calling convention to use.
191 * ctypes.default_abi corresponds to the cdecl convention, and in almost all
192 * cases is the correct choice. ctypes.stdcall_abi is provided for calling
193 * stdcall functions on Win32, and implies stdcall symbol name decoration;
194 * ctypes.winapi_abi is just stdcall but without decoration.
195 */
196 enum ABICode {
197 ABI_DEFAULT,
198 ABI_STDCALL,
199 ABI_WINAPI,
200 INVALID_ABI
201 };
203 enum TypeCode {
204 TYPE_void_t,
205 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
206 #include "ctypes/typedefs.h"
207 TYPE_pointer,
208 TYPE_function,
209 TYPE_array,
210 TYPE_struct
211 };
213 // Descriptor of one field in a StructType. The name of the field is stored
214 // as the key to the hash entry.
215 struct FieldInfo
216 {
217 JS::Heap<JSObject*> mType; // CType of the field
218 size_t mIndex; // index of the field in the struct (first is 0)
219 size_t mOffset; // offset of the field in the struct, in bytes
220 };
222 struct UnbarrieredFieldInfo
223 {
224 JSObject* mType; // CType of the field
225 size_t mIndex; // index of the field in the struct (first is 0)
226 size_t mOffset; // offset of the field in the struct, in bytes
227 };
228 static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo),
229 "UnbarrieredFieldInfo should be the same as FieldInfo but with unbarriered mType");
231 // Hash policy for FieldInfos.
232 struct FieldHashPolicy : DefaultHasher<JSFlatString*>
233 {
234 typedef JSFlatString* Key;
235 typedef Key Lookup;
237 static uint32_t hash(const Lookup &l) {
238 const jschar* s = l->chars();
239 size_t n = l->length();
240 uint32_t hash = 0;
241 for (; n > 0; s++, n--)
242 hash = hash * 33 + *s;
243 return hash;
244 }
246 static bool match(const Key &k, const Lookup &l) {
247 if (k == l)
248 return true;
250 if (k->length() != l->length())
251 return false;
253 return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
254 }
255 };
257 typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
259 // Descriptor of ABI, return type, argument types, and variadicity for a
260 // FunctionType.
261 struct FunctionInfo
262 {
263 // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
264 // FunctionType::Call, when mIsVariadic. Not always consistent with
265 // mFFITypes, due to lazy initialization when mIsVariadic.
266 ffi_cif mCIF;
268 // Calling convention of the function. Convert to ffi_abi using GetABI
269 // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing.
270 JS::Heap<JSObject*> mABI;
272 // The CType of the value returned by the function.
273 JS::Heap<JSObject*> mReturnType;
275 // A fixed array of known parameter types, excluding any variadic
276 // parameters (if mIsVariadic).
277 Array<JS::Heap<JSObject*> > mArgTypes;
279 // A variable array of ffi_type*s corresponding to both known parameter
280 // types and dynamic (variadic) parameter types. Longer than mArgTypes
281 // only if mIsVariadic.
282 Array<ffi_type*> mFFITypes;
284 // Flag indicating whether the function behaves like a C function with
285 // ... as the final formal parameter.
286 bool mIsVariadic;
287 };
289 // Parameters necessary for invoking a JS function from a C closure.
290 struct ClosureInfo
291 {
292 JSContext* cx; // JSContext to use
293 JSRuntime* rt; // Used in the destructor, where cx might have already
294 // been GCed.
295 JS::Heap<JSObject*> closureObj; // CClosure object
296 JS::Heap<JSObject*> typeObj; // FunctionType describing the C function
297 JS::Heap<JSObject*> thisObj; // 'this' object to use for the JS function call
298 JS::Heap<JSObject*> jsfnObj; // JS function
299 void* errResult; // Result that will be returned if the closure throws
300 ffi_closure* closure; // The C closure itself
302 // Anything conditionally freed in the destructor should be initialized to
303 // nullptr here.
304 ClosureInfo(JSRuntime* runtime)
305 : rt(runtime)
306 , errResult(nullptr)
307 , closure(nullptr)
308 {}
310 ~ClosureInfo() {
311 if (closure)
312 ffi_closure_free(closure);
313 js_free(errResult);
314 }
315 };
317 bool IsCTypesGlobal(HandleValue v);
318 bool IsCTypesGlobal(JSObject* obj);
320 JSCTypesCallbacks* GetCallbacks(JSObject* obj);
322 /*******************************************************************************
323 ** JSClass reserved slot definitions
324 *******************************************************************************/
326 enum CTypesGlobalSlot {
327 SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct
328 SLOT_ERRNO = 1, // jsval for latest |errno|
329 SLOT_LASTERROR = 2, // jsval for latest |GetLastError|, used only with Windows
330 CTYPESGLOBAL_SLOTS
331 };
333 enum CABISlot {
334 SLOT_ABICODE = 0, // ABICode of the CABI object
335 CABI_SLOTS
336 };
338 enum CTypeProtoSlot {
339 SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object
340 SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object
341 SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object
342 SLOT_FUNCTIONPROTO = 3, // ctypes.FunctionType.prototype object
343 SLOT_CDATAPROTO = 4, // ctypes.CData.prototype object
344 SLOT_POINTERDATAPROTO = 5, // common ancestor of all CData objects of PointerType
345 SLOT_ARRAYDATAPROTO = 6, // common ancestor of all CData objects of ArrayType
346 SLOT_STRUCTDATAPROTO = 7, // common ancestor of all CData objects of StructType
347 SLOT_FUNCTIONDATAPROTO = 8, // common ancestor of all CData objects of FunctionType
348 SLOT_INT64PROTO = 9, // ctypes.Int64.prototype object
349 SLOT_UINT64PROTO = 10, // ctypes.UInt64.prototype object
350 SLOT_CTYPES = 11, // ctypes object
351 SLOT_OURDATAPROTO = 12, // the data prototype corresponding to this object
352 CTYPEPROTO_SLOTS
353 };
355 enum CTypeSlot {
356 SLOT_PROTO = 0, // 'prototype' property of the CType object
357 SLOT_TYPECODE = 1, // TypeCode of the CType object
358 SLOT_FFITYPE = 2, // ffi_type representing the type
359 SLOT_NAME = 3, // name of the type
360 SLOT_SIZE = 4, // size of the type, in bytes
361 SLOT_ALIGN = 5, // alignment of the type, in bytes
362 SLOT_PTR = 6, // cached PointerType object for type.ptr
363 // Note that some of the slots below can overlap, since they're for
364 // mutually exclusive types.
365 SLOT_TARGET_T = 7, // (PointerTypes only) 'targetType' property
366 SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property
367 SLOT_LENGTH = 8, // (ArrayTypes only) 'length' property
368 SLOT_FIELDS = 7, // (StructTypes only) 'fields' property
369 SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table
370 SLOT_FNINFO = 7, // (FunctionTypes only) FunctionInfo struct
371 SLOT_ARGS_T = 8, // (FunctionTypes only) 'argTypes' property (cached)
372 CTYPE_SLOTS
373 };
375 enum CDataSlot {
376 SLOT_CTYPE = 0, // CType object representing the underlying type
377 SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
378 SLOT_DATA = 2, // pointer to a buffer containing the binary data
379 SLOT_OWNS = 3, // JSVAL_TRUE if this CData owns its own buffer
380 CDATA_SLOTS
381 };
383 enum CClosureSlot {
384 SLOT_CLOSUREINFO = 0, // ClosureInfo struct
385 CCLOSURE_SLOTS
386 };
388 enum CDataFinalizerSlot {
389 // The type of the value (a CType JSObject).
390 // We hold it to permit ImplicitConvert and ToSource.
391 SLOT_DATAFINALIZER_VALTYPE = 0,
392 // The type of the function used at finalization (a CType JSObject).
393 // We hold it to permit |ToSource|.
394 SLOT_DATAFINALIZER_CODETYPE = 1,
395 CDATAFINALIZER_SLOTS
396 };
398 enum TypeCtorSlot {
399 SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
400 // JSFunction objects always get exactly two slots.
401 };
403 enum Int64Slot {
404 SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
405 INT64_SLOTS
406 };
408 enum Int64FunctionSlot {
409 SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
410 // JSFunction objects always get exactly two slots.
411 };
413 /*******************************************************************************
414 ** Object API definitions
415 *******************************************************************************/
417 namespace CType {
418 JSObject* Create(JSContext* cx, HandleObject typeProto, HandleObject dataProto,
419 TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType);
421 JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName,
422 JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type,
423 jsval size, jsval align, ffi_type* ffiType);
425 bool IsCType(JSObject* obj);
426 bool IsCTypeProto(JSObject* obj);
427 TypeCode GetTypeCode(JSObject* typeObj);
428 bool TypesEqual(JSObject* t1, JSObject* t2);
429 size_t GetSize(JSObject* obj);
430 bool GetSafeSize(JSObject* obj, size_t* result);
431 bool IsSizeDefined(JSObject* obj);
432 size_t GetAlignment(JSObject* obj);
433 ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
434 JSString* GetName(JSContext* cx, HandleObject obj);
435 JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot);
436 JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
437 JSCTypesCallbacks* GetCallbacksFromType(JSObject* obj);
438 }
440 namespace PointerType {
441 JSObject* CreateInternal(JSContext* cx, HandleObject baseType);
443 JSObject* GetBaseType(JSObject* obj);
444 }
446 namespace ArrayType {
447 JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length,
448 bool lengthDefined);
450 JSObject* GetBaseType(JSObject* obj);
451 size_t GetLength(JSObject* obj);
452 bool GetSafeLength(JSObject* obj, size_t* result);
453 ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
454 }
456 namespace StructType {
457 bool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
459 const FieldInfoHash* GetFieldInfo(JSObject* obj);
460 const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
461 JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
462 ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
463 }
465 namespace FunctionType {
466 JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype,
467 jsval* argtypes, unsigned arglen);
469 JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
470 JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
472 FunctionInfo* GetFunctionInfo(JSObject* obj);
473 void BuildSymbolName(JSString* name, JSObject* typeObj,
474 AutoCString& result);
475 }
477 namespace CClosure {
478 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj,
479 HandleObject thisObj, jsval errVal, PRFuncPtr* fnptr);
480 }
482 namespace CData {
483 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject refObj,
484 void* data, bool ownResult);
486 JSObject* GetCType(JSObject* dataObj);
487 void* GetData(JSObject* dataObj);
488 bool IsCData(JSObject* obj);
489 bool IsCData(HandleValue v);
490 bool IsCDataProto(JSObject* obj);
492 // Attached by JSAPI as the function 'ctypes.cast'
493 bool Cast(JSContext* cx, unsigned argc, jsval* vp);
494 // Attached by JSAPI as the function 'ctypes.getRuntime'
495 bool GetRuntime(JSContext* cx, unsigned argc, jsval* vp);
496 }
498 namespace Int64 {
499 bool IsInt64(JSObject* obj);
500 }
502 namespace UInt64 {
503 bool IsUInt64(JSObject* obj);
504 }
506 }
507 }
509 #endif /* ctypes_CTypes_h */