Bug 1817727 - Disable test_filename_sanitize.js on mac because of permafailures....
[gecko.git] / js / src / ctypes / CTypes.h
blob665aed537e40902418c4942f63492d1441825f35
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef ctypes_CTypes_h
8 #define ctypes_CTypes_h
10 #include "mozilla/Sprintf.h"
11 #include "mozilla/Vector.h"
13 #include "ffi.h"
14 #include "prlink.h"
16 #include "ctypes/typedefs.h"
17 #include "gc/ZoneAllocator.h"
18 #include "js/AllocPolicy.h"
19 #include "js/GCHashTable.h"
20 #include "js/UniquePtr.h"
21 #include "js/Vector.h"
22 #include "vm/JSObject.h"
23 #include "vm/StringType.h"
25 namespace JS {
26 struct CTypesCallbacks;
27 } // namespace JS
29 namespace js {
30 namespace ctypes {
32 /*******************************************************************************
33 ** Utility classes
34 *******************************************************************************/
36 // CTypes builds a number of strings. StringBuilder allows repeated appending
37 // with a single error check at the end. Only the Vector methods required for
38 // building the string are exposed.
40 template <class CharT, size_t N>
41 class StringBuilder {
42 Vector<CharT, N, SystemAllocPolicy> v;
44 // Have any (OOM) errors been encountered while constructing this string?
45 bool errored{false};
47 #ifdef DEBUG
48 // Have we finished building this string?
49 bool finished{false};
51 // Did we check for errors?
52 mutable bool checked{false};
53 #endif
55 public:
56 explicit operator bool() const {
57 #ifdef DEBUG
58 checked = true;
59 #endif
60 return !errored;
63 // Handle the result of modifying the string, by remembering the persistent
64 // errored status.
65 bool handle(bool result) {
66 MOZ_ASSERT(!finished);
67 if (!result) {
68 errored = true;
70 return result;
73 bool resize(size_t n) { return handle(v.resize(n)); }
75 CharT& operator[](size_t index) { return v[index]; }
76 const CharT& operator[](size_t index) const { return v[index]; }
77 size_t length() const { return v.length(); }
79 template <typename U>
80 [[nodiscard]] bool append(U&& u) {
81 return handle(v.append(u));
84 template <typename U>
85 [[nodiscard]] bool append(const U* begin, const U* end) {
86 return handle(v.append(begin, end));
89 template <typename U>
90 [[nodiscard]] bool append(const U* begin, size_t len) {
91 return handle(v.append(begin, len));
94 CharT* begin() {
95 MOZ_ASSERT(!finished);
96 return v.begin();
99 // finish() produces the results of the string building, and is required as
100 // the last thing before the string contents are used. The StringBuilder must
101 // be checked for errors before calling this, however.
102 Vector<CharT, N, SystemAllocPolicy>&& finish() {
103 MOZ_ASSERT(!errored);
104 MOZ_ASSERT(!finished);
105 MOZ_ASSERT(checked);
106 #ifdef DEBUG
107 finished = true;
108 #endif
109 return std::move(v);
113 // Note that these strings do not have any inline storage, because we use move
114 // constructors to pass the data around and inline storage would necessitate
115 // copying.
116 typedef StringBuilder<char16_t, 0> AutoString;
117 typedef StringBuilder<char, 0> AutoCString;
119 typedef Vector<char16_t, 0, SystemAllocPolicy> AutoStringChars;
120 typedef Vector<char, 0, SystemAllocPolicy> AutoCStringChars;
122 // Convenience functions to append, insert, and compare Strings.
123 template <class T, size_t N, size_t ArrayLength>
124 void AppendString(JSContext* cx, StringBuilder<T, N>& v,
125 const char (&array)[ArrayLength]) {
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;
133 for (size_t i = 0; i < alen; ++i) {
134 v[i + vlen] = array[i];
138 template <class T, size_t N>
139 void AppendChars(StringBuilder<T, N>& v, const char c, size_t count) {
140 size_t vlen = v.length();
141 if (!v.resize(vlen + count)) {
142 return;
145 for (size_t i = 0; i < count; ++i) {
146 v[i + vlen] = c;
150 template <class T, size_t N>
151 void AppendUInt(StringBuilder<T, N>& v, unsigned n) {
152 char array[16];
153 size_t alen = SprintfLiteral(array, "%u", n);
154 size_t vlen = v.length();
155 if (!v.resize(vlen + alen)) {
156 return;
159 for (size_t i = 0; i < alen; ++i) {
160 v[i + vlen] = array[i];
164 template <class T, size_t N, size_t M, class AP>
165 void AppendString(JSContext* cx, StringBuilder<T, N>& v,
166 mozilla::Vector<T, M, AP>& w) {
167 if (!v.append(w.begin(), w.length())) {
168 return;
172 template <size_t N>
173 void AppendString(JSContext* cx, StringBuilder<char16_t, N>& v, JSString* str) {
174 MOZ_ASSERT(str);
175 JSLinearString* linear = str->ensureLinear(cx);
176 if (!linear) {
177 return;
179 JS::AutoCheckCannotGC nogc;
180 if (linear->hasLatin1Chars()) {
181 if (!v.append(linear->latin1Chars(nogc), linear->length())) {
182 return;
184 } else {
185 if (!v.append(linear->twoByteChars(nogc), linear->length())) {
186 return;
191 template <size_t N>
192 void AppendString(JSContext* cx, StringBuilder<char, N>& v, JSString* str) {
193 MOZ_ASSERT(str);
194 size_t vlen = v.length();
195 size_t alen = str->length();
196 if (!v.resize(vlen + alen)) {
197 return;
200 JSLinearString* linear = str->ensureLinear(cx);
201 if (!linear) {
202 return;
205 JS::AutoCheckCannotGC nogc;
206 if (linear->hasLatin1Chars()) {
207 const Latin1Char* chars = linear->latin1Chars(nogc);
208 for (size_t i = 0; i < alen; ++i) {
209 v[i + vlen] = char(chars[i]);
211 } else {
212 const char16_t* chars = linear->twoByteChars(nogc);
213 for (size_t i = 0; i < alen; ++i) {
214 v[i + vlen] = char(chars[i]);
219 template <class T, size_t N, size_t ArrayLength>
220 void PrependString(JSContext* cx, StringBuilder<T, N>& v,
221 const char (&array)[ArrayLength]) {
222 // Don't include the trailing '\0'.
223 size_t alen = ArrayLength - 1;
224 size_t vlen = v.length();
225 if (!v.resize(vlen + alen)) {
226 return;
229 // Move vector data forward. This is safe since we've already resized.
230 memmove(v.begin() + alen, v.begin(), vlen * sizeof(T));
232 // Copy data to insert.
233 for (size_t i = 0; i < alen; ++i) {
234 v[i] = array[i];
238 template <size_t N>
239 void PrependString(JSContext* cx, StringBuilder<char16_t, N>& v,
240 JSString* str) {
241 MOZ_ASSERT(str);
242 size_t vlen = v.length();
243 size_t alen = str->length();
244 if (!v.resize(vlen + alen)) {
245 return;
248 JSLinearString* linear = str->ensureLinear(cx);
249 if (!linear) {
250 return;
253 // Move vector data forward. This is safe since we've already resized.
254 memmove(v.begin() + alen, v.begin(), vlen * sizeof(char16_t));
256 // Copy data to insert.
257 CopyChars(v.begin(), *linear);
260 [[nodiscard]] bool ReportErrorIfUnpairedSurrogatePresent(JSContext* cx,
261 JSLinearString* str);
263 [[nodiscard]] JSObject* GetThisObject(JSContext* cx, const CallArgs& args,
264 const char* msg);
266 /*******************************************************************************
267 ** Function and struct API definitions
268 *******************************************************************************/
270 // for JS error reporting
271 enum ErrorNum {
272 #define MSG_DEF(name, count, exception, format) name,
273 #include "ctypes/ctypes.msg"
274 #undef MSG_DEF
275 CTYPESERR_LIMIT
279 * ABI constants that specify the calling convention to use.
280 * ctypes.default_abi corresponds to the cdecl convention, and in almost all
281 * cases is the correct choice. ctypes.stdcall_abi is provided for calling
282 * stdcall functions on Win32, and implies stdcall symbol name decoration;
283 * ctypes.winapi_abi is just stdcall but without decoration.
285 enum ABICode {
286 ABI_DEFAULT,
287 ABI_STDCALL,
288 ABI_THISCALL,
289 ABI_WINAPI,
290 INVALID_ABI
293 enum TypeCode {
294 TYPE_void_t,
295 #define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
296 CTYPES_FOR_EACH_TYPE(DEFINE_TYPE)
297 #undef DEFINE_TYPE
298 TYPE_pointer,
299 TYPE_function,
300 TYPE_array,
301 TYPE_struct
304 // Descriptor of one field in a StructType. The name of the field is stored
305 // as the key to the hash entry.
306 struct FieldInfo {
307 HeapPtr<JSObject*> mType; // CType of the field
308 size_t mIndex; // index of the field in the struct (first is 0)
309 size_t mOffset; // offset of the field in the struct, in bytes
311 void trace(JSTracer* trc) { TraceEdge(trc, &mType, "fieldType"); }
314 struct UnbarrieredFieldInfo {
315 JSObject* mType; // CType of the field
316 size_t mIndex; // index of the field in the struct (first is 0)
317 size_t mOffset; // offset of the field in the struct, in bytes
319 static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo),
320 "UnbarrieredFieldInfo should be the same as FieldInfo but with "
321 "unbarriered mType");
323 // Hash policy for FieldInfos.
324 struct FieldHashPolicy {
325 using Key = JSLinearString*;
326 using Lookup = Key;
328 static HashNumber hash(const Lookup& l) { return js::HashStringChars(l); }
330 static bool match(const Key& k, const Lookup& l) {
331 return js::EqualStrings(k, l);
335 using FieldInfoHash = GCHashMap<js::HeapPtr<JSLinearString*>, FieldInfo,
336 FieldHashPolicy, CellAllocPolicy>;
338 // Descriptor of ABI, return type, argument types, and variadicity for a
339 // FunctionType.
340 struct FunctionInfo {
341 explicit FunctionInfo(JS::Zone* zone) : mArgTypes(zone), mFFITypes(zone) {}
343 // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in
344 // FunctionType::Call, when mIsVariadic. Not always consistent with
345 // mFFITypes, due to lazy initialization when mIsVariadic.
346 ffi_cif mCIF;
348 // Calling convention of the function. Convert to ffi_abi using GetABI
349 // and ObjectValue. Stored as a JSObject* for ease of tracing.
350 HeapPtr<JSObject*> mABI;
352 // The CType of the value returned by the function.
353 HeapPtr<JSObject*> mReturnType;
355 // A fixed array of known parameter types, excluding any variadic
356 // parameters (if mIsVariadic).
357 GCVector<HeapPtr<JSObject*>, 0, CellAllocPolicy> mArgTypes;
359 // A variable array of ffi_type*s corresponding to both known parameter
360 // types and dynamic (variadic) parameter types. Longer than mArgTypes
361 // only if mIsVariadic.
362 Vector<ffi_type*, 0, CellAllocPolicy> mFFITypes;
364 // Flag indicating whether the function behaves like a C function with
365 // ... as the final formal parameter.
366 bool mIsVariadic;
369 // Parameters necessary for invoking a JS function from a C closure.
370 struct ClosureInfo {
371 JSContext* cx;
372 HeapPtr<JSObject*> closureObj; // CClosure object
373 HeapPtr<JSObject*> typeObj; // FunctionType describing the C function
374 HeapPtr<JSObject*> thisObj; // 'this' object to use for the JS function call
375 HeapPtr<JSObject*> jsfnObj; // JS function
376 void* errResult; // Result that will be returned if the closure throws
377 ffi_closure* closure; // The C closure itself
379 // Anything conditionally freed in the destructor should be initialized to
380 // nullptr here.
381 explicit ClosureInfo(JSContext* context)
382 : cx(context), errResult(nullptr), closure(nullptr) {}
384 ~ClosureInfo() {
385 if (closure) {
386 ffi_closure_free(closure);
388 js_free(errResult);
392 bool IsCTypesGlobal(HandleValue v);
393 bool IsCTypesGlobal(JSObject* obj);
395 const JS::CTypesCallbacks* GetCallbacks(JSObject* obj);
397 /*******************************************************************************
398 ** JSClass reserved slot definitions
399 *******************************************************************************/
401 enum CTypesGlobalSlot {
402 SLOT_CALLBACKS = 0, // pointer to JS::CTypesCallbacks struct
403 SLOT_ERRNO = 1, // Value for latest |errno|
404 SLOT_LASTERROR =
405 2, // Value for latest |GetLastError|, used only with Windows
406 CTYPESGLOBAL_SLOTS
409 enum CABISlot {
410 SLOT_ABICODE = 0, // ABICode of the CABI object
411 CABI_SLOTS
414 enum CTypeProtoSlot {
415 SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object
416 SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object
417 SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object
418 SLOT_FUNCTIONPROTO = 3, // ctypes.FunctionType.prototype object
419 SLOT_CDATAPROTO = 4, // ctypes.CData.prototype object
420 SLOT_POINTERDATAPROTO =
421 5, // common ancestor of all CData objects of PointerType
422 SLOT_ARRAYDATAPROTO = 6, // common ancestor of all CData objects of ArrayType
423 SLOT_STRUCTDATAPROTO =
424 7, // common ancestor of all CData objects of StructType
425 SLOT_FUNCTIONDATAPROTO =
426 8, // common ancestor of all CData objects of FunctionType
427 SLOT_INT64PROTO = 9, // ctypes.Int64.prototype object
428 SLOT_UINT64PROTO = 10, // ctypes.UInt64.prototype object
429 SLOT_CTYPES = 11, // ctypes object
430 SLOT_OURDATAPROTO = 12, // the data prototype corresponding to this object
431 CTYPEPROTO_SLOTS
434 enum CTypeSlot {
435 SLOT_PROTO = 0, // 'prototype' property of the CType object
436 SLOT_TYPECODE = 1, // TypeCode of the CType object
437 SLOT_FFITYPE = 2, // ffi_type representing the type
438 SLOT_NAME = 3, // name of the type
439 SLOT_SIZE = 4, // size of the type, in bytes
440 SLOT_ALIGN = 5, // alignment of the type, in bytes
441 SLOT_PTR = 6, // cached PointerType object for type.ptr
442 // Note that some of the slots below can overlap, since they're for
443 // mutually exclusive types.
444 SLOT_TARGET_T = 7, // (PointerTypes only) 'targetType' property
445 SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property
446 SLOT_LENGTH = 8, // (ArrayTypes only) 'length' property
447 SLOT_FIELDS = 7, // (StructTypes only) 'fields' property
448 SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table
449 SLOT_FNINFO = 7, // (FunctionTypes only) FunctionInfo struct
450 SLOT_ARGS_T = 8, // (FunctionTypes only) 'argTypes' property (cached)
451 CTYPE_SLOTS
454 enum CDataSlot {
455 SLOT_CTYPE = 0, // CType object representing the underlying type
456 SLOT_REFERENT = 1, // JSObject this object must keep alive, if any
457 SLOT_DATA = 2, // pointer to a buffer containing the binary data
458 SLOT_OWNS = 3, // TrueValue() if this CData owns its own buffer
459 SLOT_FUNNAME = 4, // JSString representing the function name
460 CDATA_SLOTS
463 enum CClosureSlot {
464 SLOT_CLOSUREINFO = 0, // ClosureInfo struct
465 CCLOSURE_SLOTS
468 enum CDataFinalizerSlot {
469 // PrivateValue storing CDataFinalizer::Private* pointer or UndefinedValue.
470 SLOT_DATAFINALIZER_PRIVATE = 0,
471 // The type of the value (a CType JSObject).
472 // We hold it to permit ImplicitConvert and ToSource.
473 SLOT_DATAFINALIZER_VALTYPE = 1,
474 // The type of the function used at finalization (a CType JSObject).
475 // We hold it to permit |ToSource|.
476 SLOT_DATAFINALIZER_CODETYPE = 2,
477 CDATAFINALIZER_SLOTS
480 enum TypeCtorSlot {
481 SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype
482 // JSFunction objects always get exactly two slots.
485 enum Int64Slot {
486 SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
487 INT64_SLOTS
490 enum Int64FunctionSlot {
491 SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
492 // JSFunction objects always get exactly two slots.
495 /*******************************************************************************
496 ** Object API definitions
497 *******************************************************************************/
499 namespace CType {
500 JSObject* Create(JSContext* cx, HandleObject typeProto, HandleObject dataProto,
501 TypeCode type, JSString* name, HandleValue size,
502 HandleValue align, ffi_type* ffiType);
504 JSObject* DefineBuiltin(JSContext* cx, HandleObject ctypesObj,
505 const char* propName, JSObject* typeProto,
506 JSObject* dataProto, const char* name, TypeCode type,
507 HandleValue size, HandleValue align, ffi_type* ffiType);
509 bool IsCType(JSObject* obj);
510 bool IsCTypeProto(JSObject* obj);
511 TypeCode GetTypeCode(JSObject* typeObj);
512 bool TypesEqual(JSObject* t1, JSObject* t2);
513 size_t GetSize(JSObject* obj);
514 [[nodiscard]] bool GetSafeSize(JSObject* obj, size_t* result);
515 bool IsSizeDefined(JSObject* obj);
516 size_t GetAlignment(JSObject* obj);
517 ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
518 JSString* GetName(JSContext* cx, HandleObject obj);
519 JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot);
520 JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
521 const JS::CTypesCallbacks* GetCallbacksFromType(JSObject* obj);
522 } // namespace CType
524 namespace PointerType {
525 JSObject* CreateInternal(JSContext* cx, HandleObject baseType);
527 JSObject* GetBaseType(JSObject* obj);
528 } // namespace PointerType
530 using UniquePtrFFIType = UniquePtr<ffi_type>;
532 namespace ArrayType {
533 JSObject* CreateInternal(JSContext* cx, HandleObject baseType, size_t length,
534 bool lengthDefined);
536 JSObject* GetBaseType(JSObject* obj);
537 size_t GetLength(JSObject* obj);
538 [[nodiscard]] bool GetSafeLength(JSObject* obj, size_t* result);
539 UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj);
540 } // namespace ArrayType
542 namespace StructType {
543 [[nodiscard]] bool DefineInternal(JSContext* cx, JSObject* typeObj,
544 JSObject* fieldsObj);
546 const FieldInfoHash* GetFieldInfo(JSObject* obj);
547 const FieldInfo* LookupField(JSContext* cx, JSObject* obj,
548 JSLinearString* name);
549 JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
550 UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj);
551 } // namespace StructType
553 namespace FunctionType {
554 JSObject* CreateInternal(JSContext* cx, HandleValue abi, HandleValue rtype,
555 const HandleValueArray& args);
557 JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
558 JSObject* refObj, PRFuncPtr fnptr,
559 JSObject* result);
561 FunctionInfo* GetFunctionInfo(JSObject* obj);
562 void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
563 AutoCString& result);
564 } // namespace FunctionType
566 namespace CClosure {
567 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj,
568 HandleObject thisObj, HandleValue errVal, PRFuncPtr* fnptr);
569 } // namespace CClosure
571 namespace CData {
572 JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject refObj,
573 void* data, bool ownResult);
575 JSObject* GetCType(JSObject* dataObj);
576 void* GetData(JSObject* dataObj);
577 bool IsCData(JSObject* obj);
578 bool IsCDataMaybeUnwrap(MutableHandleObject obj);
579 bool IsCData(HandleValue v);
580 bool IsCDataProto(JSObject* obj);
582 // Attached by JSAPI as the function 'ctypes.cast'
583 [[nodiscard]] bool Cast(JSContext* cx, unsigned argc, Value* vp);
584 // Attached by JSAPI as the function 'ctypes.getRuntime'
585 [[nodiscard]] bool GetRuntime(JSContext* cx, unsigned argc, Value* vp);
586 } // namespace CData
588 namespace Int64 {
589 bool IsInt64(JSObject* obj);
590 } // namespace Int64
592 namespace UInt64 {
593 bool IsUInt64(JSObject* obj);
594 } // namespace UInt64
596 } // namespace ctypes
597 } // namespace js
599 #endif /* ctypes_CTypes_h */