diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index b48961993ed7..882583ca4cce 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -21,7 +21,6 @@ * * Contributor(s): * Dan Witte - * David Rajchenbach-Teller * * 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 @@ -63,9 +62,6 @@ #include #endif -#include "mozilla/StandardInteger.h" -#include "mozilla/Scoped.h" - using namespace std; namespace js { @@ -98,7 +94,7 @@ namespace CType { static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp); - /* + /** * Get the global "ctypes" object. * * |obj| must be a CType object. @@ -189,8 +185,7 @@ namespace CData { static JSBool Address(JSContext* cx, unsigned argc, jsval* vp); static JSBool ReadString(JSContext* cx, unsigned argc, jsval* vp); static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp); - static JSString *GetSourceString(JSContext *cx, JSObject *typeObj, - void *data); + static JSBool ErrnoGetter(JSContext* cx, JSObject *obj, jsid idval, jsval* vp); @@ -200,118 +195,6 @@ namespace CData { #endif // defined(XP_WIN) } -namespace CDataFinalizer { - /* - * Attach a C function as a finalizer to a JS object. - * - * This function is available from JS as |ctypes.withFinalizer|. - * - * JavaScript signature: - * function(CData, CData): CDataFinalizer - * value finalizer finalizable - * - * Where |finalizer| is a one-argument function taking a value - * with the same type as |value|. - */ - static JSBool Construct(JSContext* cx, unsigned argc, jsval *vp); - - /* - * Private data held by |CDataFinalizer|. - * - * See also |enum CDataFinalizerSlot| for the slots of - * |CDataFinalizer|. - * - * Note: the private data may be NULL, if |dispose|, |forget| or the - * finalizer has already been called. - */ - struct Private { - /* - * The C data to pass to the code. - * Finalization/|dispose|/|forget| release this memory. - */ - void *cargs; - - /* - * The total size of the buffer pointed by |cargs| - */ - size_t cargs_size; - - /* - * Low-level signature information. - * Finalization/|dispose|/|forget| release this memory. - */ - ffi_cif CIF; - - /* - * The C function to invoke during finalization. - * Do not deallocate this. - */ - uintptr_t code; - - /* - * A buffer for holding the return value. - * Finalization/|dispose|/|forget| release this memory. - */ - void *rvalue; - }; - - /* - * Methods of instances of |CDataFinalizer| - */ - namespace Methods { - static JSBool Dispose(JSContext* cx, unsigned argc, jsval *vp); - static JSBool Forget(JSContext* cx, unsigned argc, jsval *vp); - static JSBool ToSource(JSContext* cx, unsigned argc, jsval *vp); - static JSBool ToString(JSContext* cx, unsigned argc, jsval *vp); - } - - /* - * Utility functions - * - * @return true if |obj| is a CDataFinalizer, false otherwise. - */ - static bool IsCDataFinalizer(JSObject *obj); - - /* - * Clean up the finalization information of a CDataFinalizer. - * - * Used by |Finalize|, |Dispose| and |Forget|. - * - * @param p The private information of the CDataFinalizer. If NULL, - * this function does nothing. - * @param obj Either NULL, if the object should not be cleaned up (i.e. - * during finalization) or a CDataFinalizer JSObject. Always use NULL - * if you are calling from a finalizer. - */ - static void Cleanup(Private *p, JSObject *obj); - - /* - * Perform the actual call to the finalizer code. - */ - static void CallFinalizer(CDataFinalizer::Private *p, - int* errnoStatus, - int32_t* lastErrorStatus); - - /* - * Return the CType of a CDataFinalizer object, or NULL if the object - * has been cleaned-up already. - */ - static JSObject *GetCType(JSContext *cx, JSObject *obj); - - /* - * Perform finalization of a |CDataFinalizer| - */ - static void Finalize(JSFreeOp *fop, JSObject *obj); - - /* - * Return the jsval contained by this finalizer. - * - * Note that the jsval is actually not recorded, but converted back from C. - */ - static bool GetValue(JSContext *cx, JSObject *obj, jsval *result); - } - - // Int64Base provides functions common to Int64 and UInt64. namespace Int64Base { JSObject* Construct(JSContext* cx, JSObject* proto, uint64_t data, @@ -417,30 +300,6 @@ static JSClass sCClosureClass = { NULL, NULL, NULL, NULL, CClosure::Trace }; -/* - * Class representing the prototype of CDataFinalizer. - */ -static JSClass sCDataFinalizerProtoClass = { - "CDataFinalizer", - 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub -}; - -/* - * Class representing instances of CDataFinalizer. - * - * Instances of CDataFinalizer have both private data (with type - * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|). - */ -static JSClass sCDataFinalizerClass = { - "CDataFinalizer", - JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CDataFinalizer::Finalize, -}; - - #define CTYPESFN_FLAGS \ (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) @@ -453,9 +312,6 @@ static JSClass sCDataFinalizerClass = { #define CDATAFN_FLAGS \ (JSPROP_READONLY | JSPROP_PERMANENT) -#define CDATAFINALIZERFN_FLAGS \ - (JSPROP_READONLY | JSPROP_PERMANENT) - static JSPropertySpec sCTypeProps[] = { { "name", 0, CTYPESPROP_FLAGS, CType::NameGetter, NULL }, { "size", 0, CTYPESPROP_FLAGS, CType::SizeGetter, NULL }, @@ -485,18 +341,6 @@ static JSFunctionSpec sCDataFunctions[] = { JS_FS_END }; -static JSPropertySpec sCDataFinalizerProps[] = { - { 0, 0, 0, NULL, NULL } -}; - -static JSFunctionSpec sCDataFinalizerFunctions[] = { - JS_FN("dispose", CDataFinalizer::Methods::Dispose, 0, CDATAFINALIZERFN_FLAGS), - JS_FN("forget", CDataFinalizer::Methods::Forget, 0, CDATAFINALIZERFN_FLAGS), - JS_FN("toString", CDataFinalizer::Methods::ToString, 0, CDATAFINALIZERFN_FLAGS), - JS_FN("toSource", CDataFinalizer::Methods::ToSource, 0, CDATAFINALIZERFN_FLAGS), - JS_FS_END -}; - static JSFunctionSpec sPointerFunction = JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS); @@ -640,7 +484,6 @@ static JSPropertySpec sModuleProps[] = { }; static JSFunctionSpec sModuleFunctions[] = { - JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS), JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS), JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS), JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS), @@ -662,16 +505,9 @@ NewUCString(JSContext* cx, const AutoString& from) return JS_NewUCStringCopyN(cx, from.begin(), from.length()); } -/* - * Return a size rounded up to a multiple of a power of two. - * - * Note: |align| must be a power of 2. - */ JS_ALWAYS_INLINE size_t Align(size_t val, size_t align) { - // Ensure that align is a power of two. - MOZ_ASSERT(align != 0 && (align & (align - 1)) == 0); return ((val - 1) | (align - 1)) + 1; } @@ -1133,26 +969,6 @@ GetCallbacks(JSObject* obj) return static_cast(JSVAL_TO_PRIVATE(result)); } -// Utility function to access a property of an object as an object -// returns false and sets the error if the property does not exist -// or is not an object -bool GetObjectProperty(JSContext *cx, JSObject *obj, - const char *property, JSObject **result) -{ - jsval val; - if (!JS_GetProperty(cx, obj, property, &val)) { - return false; - } - - if (JSVAL_IS_PRIMITIVE(val)) { - JS_ReportError(cx, "missing or non-object field"); - return false; - } - - *result = JSVAL_TO_OBJECT(val); - return true; -} - JS_BEGIN_EXTERN_C JS_PUBLIC_API(JSBool) @@ -1176,30 +992,6 @@ JS_InitCTypesClass(JSContext* cx, JSObject* global) !JS_DefineProperties(cx, ctypes, sModuleProps)) return false; - // Set up ctypes.CDataFinalizer.prototype. - JSObject* ctor; - if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor)) { - return NULL; - } - - JSObject* prototype = JS_NewObject(cx, &sCDataFinalizerProtoClass, - NULL, ctypes); - if (!prototype) - return NULL; - - if (!JS_DefineProperties(cx, prototype, sCDataFinalizerProps) || - !JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions)) - return NULL; - - if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype), - NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) - return NULL; - - if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor), - NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) - return NULL; - - // Seal the ctypes object, to prevent modification. return JS_FreezeObject(cx, ctypes); } @@ -1481,15 +1273,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) return ConvertExact(i, result); } - if (CDataFinalizer::IsCDataFinalizer(obj)) { - jsval innerData; - if (!CDataFinalizer::GetValue(cx, obj, &innerData)) { - return false; // Nothing to convert - } - return jsvalToInteger(cx, innerData, result); - } - - return false; + return false; } if (JSVAL_IS_BOOLEAN(val)) { // Implicitly promote boolean values to 0 or 1, like C. @@ -1660,15 +1444,6 @@ jsvalToBigInteger(JSContext* cx, int64_t i = Int64Base::GetInt(obj); return ConvertExact(i, result); } - - if (CDataFinalizer::IsCDataFinalizer(obj)) { - jsval innerData; - if (!CDataFinalizer::GetValue(cx, obj, &innerData)) { - return false; // Nothing to convert - } - return jsvalToBigInteger(cx, innerData, allowString, result); - } - } return false; } @@ -2009,40 +1784,20 @@ ImplicitConvert(JSContext* cx, { JS_ASSERT(CType::IsSizeDefined(targetType)); - // First, check if val is either a CData object or a CDataFinalizer - // of type targetType. + // First, check if val is a CData object of type targetType. JSObject* sourceData = NULL; JSObject* sourceType = NULL; - if (!JSVAL_IS_PRIMITIVE(val)) { - if (CData::IsCData(JSVAL_TO_OBJECT(val))) { - sourceData = JSVAL_TO_OBJECT(val); - sourceType = CData::GetCType(sourceData); + if (!JSVAL_IS_PRIMITIVE(val) && + CData::IsCData(JSVAL_TO_OBJECT(val))) { + sourceData = JSVAL_TO_OBJECT(val); + sourceType = CData::GetCType(sourceData); - // If the types are equal, copy the buffer contained within the CData. - // (Note that the buffers may overlap partially or completely.) - if (CType::TypesEqual(sourceType, targetType)) { - size_t size = CType::GetSize(sourceType); - memmove(buffer, CData::GetData(sourceData), size); - return true; - } - } else if (CDataFinalizer::IsCDataFinalizer(JSVAL_TO_OBJECT(val))) { - sourceData = JSVAL_TO_OBJECT(val); - sourceType = CDataFinalizer::GetCType(cx, sourceData); - - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(sourceData); - - if (!p) { - // We have called |dispose| or |forget| already. - JS_ReportError(cx, "Attempting to convert an empty CDataFinalizer"); - return JS_FALSE; - } - - // If the types are equal, copy the buffer contained within the CData. - if (CType::TypesEqual(sourceType, targetType)) { - memmove(buffer, p->cargs, p->cargs_size); - return true; - } + // If the types are equal, copy the buffer contained within the CData. + // (Note that the buffers may overlap partially or completely.) + if (CType::TypesEqual(sourceType, targetType)) { + size_t size = CType::GetSize(sourceType); + memmove(buffer, CData::GetData(sourceData), size); + return true; } } @@ -6271,26 +6026,6 @@ CData::ReadString(JSContext* cx, unsigned argc, jsval* vp) return JS_TRUE; } -JSString * -CData::GetSourceString(JSContext *cx, JSObject *typeObj, void *data) -{ - // Walk the types, building up the toSource() string. - // First, we build up the type expression: - // 't.ptr' for pointers; - // 't.array([n])' for arrays; - // 'n' for structs, where n = t.name, the struct's name. (We assume this is - // bound to a variable in the current scope.) - AutoString source; - BuildTypeSource(cx, typeObj, true, source); - AppendString(source, "("); - if (!BuildDataSource(cx, typeObj, data, false, source)) - return NULL; - - AppendString(source, ")"); - - return NewUCString(cx, source); -} - JSBool CData::ToSource(JSContext* cx, unsigned argc, jsval* vp) { @@ -6311,11 +6046,24 @@ CData::ToSource(JSContext* cx, unsigned argc, jsval* vp) JSObject* typeObj = CData::GetCType(obj); void* data = CData::GetData(obj); - result = CData::GetSourceString(cx, typeObj, data); - } else { - result = JS_NewStringCopyZ(cx, "[CData proto object]"); - } + // Walk the types, building up the toSource() string. + // First, we build up the type expression: + // 't.ptr' for pointers; + // 't.array([n])' for arrays; + // 'n' for structs, where n = t.name, the struct's name. (We assume this is + // bound to a variable in the current scope.) + AutoString source; + BuildTypeSource(cx, typeObj, true, source); + AppendString(source, "("); + if (!BuildDataSource(cx, typeObj, data, false, source)) + return JS_FALSE; + AppendString(source, ")"); + + result = NewUCString(cx, source); + } + else + result = JS_NewStringCopyZ(cx, "[CData proto object]"); if (!result) return JS_FALSE; @@ -6350,511 +6098,6 @@ CData::LastErrorGetter(JSContext* cx, JSObject* obj, jsid, jsval* vp) } #endif // defined(XP_WIN) -JSBool -CDataFinalizer::Methods::ToSource(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject* objThis = JS_THIS_OBJECT(cx, vp); - if (!objThis || !CDataFinalizer::IsCDataFinalizer(objThis)) { - JS_ReportError(cx, "not a CDataFinalizer"); - return JS_FALSE; - } - - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(objThis); - - JSString *strMessage; - if (!p) { - strMessage = JS_NewStringCopyZ(cx, "ctypes.CDataFinalizer()"); - } else { - JSObject *objType = CDataFinalizer::GetCType(cx, objThis); - if (!objType) { - JS_ReportError(cx, "CDataFinalizer has no type"); - return JS_FALSE; - } - - AutoString source; - AppendString(source, "ctypes.CDataFinalizer("); - JSString *srcValue = CData::GetSourceString(cx, objType, p->cargs); - if (!srcValue) { - return JS_FALSE; - } - AppendString(source, srcValue); - AppendString(source, ", "); - jsval valCodePtrType = JS_GetReservedSlot(objThis, - SLOT_DATAFINALIZER_CODETYPE); - if (JSVAL_IS_PRIMITIVE(valCodePtrType)) { - return JS_FALSE; - } - - JSString *srcDispose = - CData::GetSourceString(cx, JSVAL_TO_OBJECT(valCodePtrType), - &(p->code)); - if (!srcDispose) { - return JS_FALSE; - } - - AppendString(source, srcDispose); - AppendString(source, ")"); - strMessage = NewUCString(cx, source); - } - - if (!strMessage) { - // This is a memory issue, no error message - return JS_FALSE; - } - - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(strMessage)); - return JS_TRUE; -} - -JSBool -CDataFinalizer::Methods::ToString(JSContext *cx, unsigned argc, jsval *vp) -{ - JSObject* objThis = JS_THIS_OBJECT(cx, vp); - if (!objThis || !CDataFinalizer::IsCDataFinalizer(objThis)) { - JS_ReportError(cx, "not a CDataFinalizer"); - return JS_FALSE; - } - - JSString *strMessage; - jsval value; - if (!JS_GetPrivate(objThis)) { - // Pre-check whether CDataFinalizer::GetValue can fail - // to avoid reporting an error when not appropriate. - strMessage = JS_NewStringCopyZ(cx, "[CDataFinalizer - empty]"); - if (!strMessage) { - return JS_FALSE; - } - } else if (!CDataFinalizer::GetValue(cx, objThis, &value)) { - JS_NOT_REACHED("Could not convert an empty CDataFinalizer"); - } else { - strMessage = JS_ValueToString(cx, value); - if (!strMessage) { - return JS_FALSE; - } - } - JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(strMessage)); - return JS_TRUE; -} - -bool -CDataFinalizer::IsCDataFinalizer(JSObject *obj) -{ - return JS_GetClass(obj) == &sCDataFinalizerClass; -} - - -JSObject * -CDataFinalizer::GetCType(JSContext *cx, JSObject *obj) -{ - MOZ_ASSERT(IsCDataFinalizer(obj)); - - jsval valData = JS_GetReservedSlot(obj, - SLOT_DATAFINALIZER_VALTYPE); - if (JSVAL_IS_VOID(valData)) { - return NULL; - } - - return JSVAL_TO_OBJECT(valData); -} - -bool -CDataFinalizer::GetValue(JSContext *cx, JSObject *obj, jsval *aResult) -{ - MOZ_ASSERT(IsCDataFinalizer(obj)); - - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(obj); - - if (!p) { - JS_ReportError(cx, "Attempting to get the value of an empty CDataFinalizer"); - return false; // We have called |dispose| or |forget| already. - } - - return ConvertToJS(cx, GetCType(cx, obj), - /*parent*/NULL, p -> cargs, false, true, aResult); -} - -/* - * Attach a C function as a finalizer to a JS object. - * - * Pseudo-JS signature: - * function(CData, CData U>): CDataFinalizer - * value, finalizer - * - * This function attaches strong references to the following values: - * - the CType of |value| - * - * Note: This function takes advantage of the fact that non-variadic - * CData functions are initialized during creation. - */ -JSBool -CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval *vp) -{ - JSObject* objSelf = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); - JSObject *objProto; - if (!GetObjectProperty(cx, objSelf, "prototype", &objProto)) { - JS_ReportError(cx, "CDataFinalizer.prototype does not exist"); - return JS_FALSE; - } - - // Get arguments - if (argc == 0) { // Special case: the empty (already finalized) object - JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NULL); - JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(objResult)); - return JS_TRUE; - } - - if (argc != 2) { - JS_ReportError(cx, "CDataFinalizer takes 2 arguments"); - return JS_FALSE; - } - - jsval* argv = JS_ARGV(cx, vp); - jsval valCodePtr = argv[1]; - if (!JSVAL_IS_OBJECT(valCodePtr) || JSVAL_IS_NULL(valCodePtr)) { - return TypeError(cx, "_a CData object_ of a function pointer type", - valCodePtr); - } - JSObject *objCodePtr = JSVAL_TO_OBJECT(valCodePtr); - - //Note: Using a custom argument formatter here would be awkward (requires - //a destructor just to uninstall the formatter). - - // 2. Extract argument type of |objCodePtr| - if (!CData::IsCData(objCodePtr)) { - return TypeError(cx, "a _CData_ object of a function pointer type", - valCodePtr); - } - JSObject *objCodePtrType = CData::GetCType(objCodePtr); - MOZ_ASSERT(objCodePtrType); - - TypeCode typCodePtr = CType::GetTypeCode(objCodePtrType); - if (typCodePtr != TYPE_pointer) { - return TypeError(cx, "a CData object of a function _pointer_ type", - OBJECT_TO_JSVAL(objCodePtrType)); - } - - JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType); - MOZ_ASSERT(objCodeType); - - TypeCode typCode = CType::GetTypeCode(objCodeType); - if (typCode != TYPE_function) { - return TypeError(cx, "a CData object of a _function_ pointer type", - OBJECT_TO_JSVAL(objCodePtrType)); - } - uintptr_t code = *reinterpret_cast(CData::GetData(objCodePtr)); - if (!code) { - return TypeError(cx, "a CData object of a _non-NULL_ function pointer type", - OBJECT_TO_JSVAL(objCodePtrType)); - } - - FunctionInfo* funInfoFinalizer = - FunctionType::GetFunctionInfo(objCodeType); - MOZ_ASSERT(funInfoFinalizer); - - if ((funInfoFinalizer->mArgTypes.length() != 1) - || (funInfoFinalizer->mIsVariadic)) { - return TypeError(cx, "a function accepting exactly one argument", - OBJECT_TO_JSVAL(objCodeType)); - } - JSObject *objArgType = funInfoFinalizer->mArgTypes[0]; - - // Invariant: At this stage, we know that funInfoFinalizer->mIsVariadic - // is |false|. Therefore, funInfoFinalizer->mCIF has already been initialized. - - bool freePointer = false; - - // 3. Perform dynamic cast of |argv[0]| into |objType|, store it in |cargs| - - size_t sizeArg; - jsval valData = argv[0]; - if (!CType::GetSafeSize(objArgType, &sizeArg)) { - return TypeError(cx, "(an object with known size)", valData); - } - - ScopedFreePtr cargs(malloc(sizeArg)); - - if (!ImplicitConvert(cx, valData, objArgType, cargs.get(), - false, &freePointer)) { - return TypeError(cx, "(an object that can be converted to the following type)", - OBJECT_TO_JSVAL(objArgType)); - } - if (freePointer) { - // Note: We could handle that case, if necessary. - JS_ReportError(cx, "Internal Error during CDataFinalizer. Object cannot be represented"); - return JS_FALSE; - } - - // 4. Prepare buffer for holding return value - - JSObject *returnType = funInfoFinalizer->mReturnType; - ScopedFreePtr rvalue; - if (CType::GetTypeCode(returnType) != TYPE_void_t) { - rvalue = malloc(Align(CType::GetSize(returnType), - sizeof(ffi_arg))); - } //Otherwise, simply do not allocate - - // 5. Create |objResult| - - JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NULL); - if (!objResult) { - return JS_FALSE; - } - - // Used by GetCType - JS_SetReservedSlot(objResult, - SLOT_DATAFINALIZER_VALTYPE, - OBJECT_TO_JSVAL(objArgType)); - - // Used by ToSource - JS_SetReservedSlot(objResult, - SLOT_DATAFINALIZER_CODETYPE, - OBJECT_TO_JSVAL(objCodePtrType)); - - ffi_abi abi; - if (!GetABI(cx, OBJECT_TO_JSVAL(funInfoFinalizer->mABI), &abi)) { - JS_ReportError(cx, "Internal Error: " - "Invalid ABI specification in CDataFinalizer"); - return false; - } - - ffi_type* rtype = CType::GetFFIType(cx, funInfoFinalizer->mReturnType); - if (!rtype) { - JS_ReportError(cx, "Internal Error: " - "Could not access ffi type of CDataFinalizer"); - return JS_FALSE; - } - - // 7. Store C information as private - ScopedFreePtr - p((CDataFinalizer::Private*)malloc(sizeof(CDataFinalizer::Private))); - - memmove(&p->CIF, &funInfoFinalizer->mCIF, sizeof(ffi_cif)); - - p->cargs = cargs.forget(); - p->rvalue = rvalue.forget(); - p->cargs_size = sizeArg; - p->code = code; - - - JS_SetPrivate(objResult, p.forget()); - JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(objResult)); - return JS_TRUE; -} - - -/* - * Actually call the finalizer. Does not perform any cleanup on the object. - * - * Preconditions: |this| must be a |CDataFinalizer|, |p| must be non-null. - * The function fails if |this| has gone through |Forget|/|Dispose| - * or |Finalize|. - * - * This function does not alter the value of |errno|/|GetLastError|. - * - * If argument |errnoStatus| is non-NULL, it receives the value of |errno| - * immediately after the call. Under Windows, if argument |lastErrorStatus| - * is non-NULL, it receives the value of |GetLastError| immediately after the - * call. On other platforms, |lastErrorStatus| is ignored. - */ -void -CDataFinalizer::CallFinalizer(CDataFinalizer::Private *p, - int* errnoStatus, - int32_t* lastErrorStatus) -{ - int savedErrno = errno; - errno = 0; -#if defined(XP_WIN) - int32_t savedLastError = GetLastError(); - SetLastError(0); -#endif // defined(XP_WIN) - - ffi_call(&p->CIF, FFI_FN(p->code), p->rvalue, &p->cargs); - - if (errnoStatus) { - *errnoStatus = errno; - } - errno = savedErrno; -#if defined(XP_WIN) - if (lastErrorStatus) { - *lastErrorStatus = GetLastError(); - } - SetLastError(savedLastError); -#endif // defined(XP_WIN) -} - -/* - * Forget the value. - * - * Preconditions: |this| must be a |CDataFinalizer|. - * The function fails if |this| has gone through |Forget|/|Dispose| - * or |Finalize|. - * - * Does not call the finalizer. Cleans up the Private memory and releases all - * strong references. - */ -JSBool -CDataFinalizer::Methods::Forget(JSContext* cx, unsigned argc, jsval *vp) -{ - if (argc != 0) { - JS_ReportError(cx, "CDataFinalizer.prototype.forget takes no arguments"); - return JS_FALSE; - } - - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !CDataFinalizer::IsCDataFinalizer(obj)) { - return TypeError(cx, "a CDataFinalizer", OBJECT_TO_JSVAL(obj)); - } - - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(obj); - - if (!p) { - JS_ReportError(cx, "forget called on an empty CDataFinalizer"); - return JS_FALSE; - } - - jsval valJSData; - if (!ConvertToJS(cx, GetCType(cx, obj), NULL, p->cargs, false, true, &valJSData)) { - JS_ReportError(cx, "CDataFinalizer value cannot be represented"); - return JS_FALSE; - } - - CDataFinalizer::Cleanup(p, obj); - - JS_SET_RVAL(cx, vp, valJSData); - return JS_TRUE; -} - -/* - * Clean up the value. - * - * Preconditions: |this| must be a |CDataFinalizer|. - * The function fails if |this| has gone through |Forget|/|Dispose| - * or |Finalize|. - * - * Calls the finalizer, cleans up the Private memory and releases all - * strong references. - */ -JSBool -CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, jsval *vp) -{ - if (argc != 0) { - JS_ReportError(cx, "CDataFinalizer.prototype.dispose takes no arguments"); - return JS_FALSE; - } - - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !CDataFinalizer::IsCDataFinalizer(obj)) { - return TypeError(cx, "a CDataFinalizer", OBJECT_TO_JSVAL(obj)); - } - - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(obj); - - if (!p) { - JS_ReportError(cx, "dispose called on an empty CDataFinalizer."); - return JS_FALSE; - } - - jsval valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(valType)); - - JSObject *objCTypes = CType::GetGlobalCTypes(cx, JSVAL_TO_OBJECT(valType)); - - jsval valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(valCodePtrType)); - JSObject *objCodePtrType = JSVAL_TO_OBJECT(valCodePtrType); - - JSObject *objCodeType = PointerType::GetBaseType(objCodePtrType); - JS_ASSERT(objCodeType); - JS_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function); - - JSObject *resultType = FunctionType::GetFunctionInfo(objCodeType)->mReturnType; - jsval result = JSVAL_VOID; - - int errnoStatus; -#if defined(XP_WIN) - int32_t lastErrorStatus; - CDataFinalizer::CallFinalizer(p, &errnoStatus, &lastErrorStatus); -#else - CDataFinalizer::CallFinalizer(p, &errnoStatus, NULL); -#endif // defined(XP_WIN) - - JS_SetReservedSlot(objCTypes, SLOT_ERRNO, INT_TO_JSVAL(errnoStatus)); -#if defined(XP_WIN) - JS_SetReservedSlot(objCTypes, SLOT_LASTERROR, INT_TO_JSVAL(lastErrorStatus)); -#endif // defined(XP_WIN) - - if (ConvertToJS(cx, resultType, NULL, p->rvalue, false, true, &result)) { - CDataFinalizer::Cleanup(p, obj); - JS_SET_RVAL(cx, vp, result); - return true; - } - CDataFinalizer::Cleanup(p, obj); - return false; -} - -/* - * Perform finalization. - * - * Preconditions: |this| must be the result of |CDataFinalizer|. - * It may have gone through |Forget|/|Dispose|. - * - * If |this| has not gone through |Forget|/|Dispose|, calls the - * finalizer, cleans up the Private memory and releases all - * strong references. - */ -void -CDataFinalizer::Finalize(JSFreeOp* fop, JSObject* obj) -{ - CDataFinalizer::Private *p = (CDataFinalizer::Private *) - JS_GetPrivate(obj); - - if (!p) { - return; - } - - CDataFinalizer::CallFinalizer(p, NULL, NULL); - CDataFinalizer::Cleanup(p, NULL); -} - -/* - * Perform cleanup of a CDataFinalizer - * - * Release strong references, cleanup |Private|. - * - * Argument |p| contains the private information of the CDataFinalizer. If NULL, - * this function does nothing. - * Argument |obj| should contain |NULL| during finalization (or in any context - * in which the object itself should not be cleaned up), or a CDataFinalizer - * object otherwise. - */ -void -CDataFinalizer::Cleanup(CDataFinalizer::Private *p, JSObject *obj) -{ - if (!p) { - return; // We have already cleaned up - } - - free(p->cargs); - free(p->rvalue); - free(p); - - if (!obj) { - return; // No slots to clean up - } - - JS_ASSERT(CDataFinalizer::IsCDataFinalizer(obj)); - - JS_SetPrivate(obj, NULL); - for (int i = 0; i < CDATAFINALIZER_SLOTS; ++i) { - JS_SetReservedSlot(obj, i, JSVAL_NULL); - } -} - - /******************************************************************************* ** Int64 and UInt64 implementation *******************************************************************************/ diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index 3a7074f352fd..f8d23fefd7fc 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -430,16 +430,6 @@ enum CClosureSlot { CCLOSURE_SLOTS }; -enum CDataFinalizerSlot { - // The type of the value (a CType JSObject). - // We hold it to permit ImplicitConvert and ToSource. - SLOT_DATAFINALIZER_VALTYPE = 0, - // The type of the function used at finalization (a CType JSObject). - // We hold it to permit |ToSource|. - SLOT_DATAFINALIZER_CODETYPE = 1, - CDATAFINALIZER_SLOTS -}; - enum TypeCtorSlot { SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype // JSFunction objects always get exactly two slots. diff --git a/toolkit/components/ctypes/tests/Makefile.in b/toolkit/components/ctypes/tests/Makefile.in index fff2dc6cc8ca..66c0f148eb95 100644 --- a/toolkit/components/ctypes/tests/Makefile.in +++ b/toolkit/components/ctypes/tests/Makefile.in @@ -53,7 +53,6 @@ NO_DIST_INSTALL = 1 CPPSRCS = jsctypes-test.cpp \ jsctypes-test-errno.cpp \ - jsctypes-test-finalizer.cpp \ $(NULL) LOCAL_INCLUDES = \ diff --git a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp b/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp deleted file mode 100644 index 82a9adcf6c21..000000000000 --- a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include "errno.h" - -#include "jsctypes-test.h" -#include "jsctypes-test-finalizer.h" -#include "jsapi.h" - -#if defined(XP_WIN) -#define snprintf _snprintf -#endif // defined(XP_WIN) - -/** - * Shared infrastructure - */ - - -/** - * An array of integers representing resources. - * - 0: unacquired - * - 1: acquired - * - < 0: error, resource has been released several times. - */ -int *gFinalizerTestResources = NULL; -char **gFinalizerTestNames = NULL; -size_t gFinalizerTestSize; - -void -test_finalizer_start(size_t size) -{ - gFinalizerTestResources = new int[size]; - gFinalizerTestNames = new char*[size]; - gFinalizerTestSize = size; - for (size_t i = 0; i < size; ++i) { - gFinalizerTestResources[i] = 0; - gFinalizerTestNames[i] = NULL; - } -} - -void -test_finalizer_stop() -{ - delete[] gFinalizerTestResources; -} - -/** - * Check if an acquired resource has been released - */ -bool -test_finalizer_resource_is_acquired(size_t i) -{ - return gFinalizerTestResources[i] == 1; -} -// Resource type: size_t - -// Acquire resource i -size_t -test_finalizer_acq_size_t(size_t i) -{ - gFinalizerTestResources[i] = 1; - return i; -} - -// Release resource i -void -test_finalizer_rel_size_t(size_t i) -{ - if (--gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } -} - -size_t -test_finalizer_rel_size_t_return_size_t(size_t i) -{ - if (-- gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } - return i; -} - -RECT -test_finalizer_rel_size_t_return_struct_t(size_t i) -{ - if (-- gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } - const PRInt32 narrowed = (PRInt32)i; - RECT result = { narrowed, narrowed, narrowed, narrowed }; - return result; -} - -bool -test_finalizer_cmp_size_t(size_t a, size_t b) -{ - return a==b; -} - -// Resource type: int32_t - -// Acquire resource i -int32_t -test_finalizer_acq_int32_t(size_t i) -{ - gFinalizerTestResources[i] = 1; - return i; -} - -// Release resource i -void -test_finalizer_rel_int32_t(int32_t i) -{ - if (--gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } -} - -bool -test_finalizer_cmp_int32_t(int32_t a, int32_t b) -{ - return a==b; -} - -// Resource type: int64_t - -// Acquire resource i -int64_t -test_finalizer_acq_int64_t(size_t i) -{ - gFinalizerTestResources[i] = 1; - return i; -} - -// Release resource i -void -test_finalizer_rel_int64_t(int64_t i) -{ - if (-- gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } -} - -bool -test_finalizer_cmp_int64_t(int64_t a, int64_t b) -{ - return a==b; -} - -// Resource type: void* - -// Acquire resource i -void* -test_finalizer_acq_ptr_t(size_t i) -{ - gFinalizerTestResources[i] = 1; - return (void*)&gFinalizerTestResources[i]; -} - -// Release resource i -void -test_finalizer_rel_ptr_t(void *i) -{ - int *as_int = (int*)i; - -- (*as_int); - if (*as_int < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } -} - -bool -test_finalizer_cmp_ptr_t(void *a, void *b) -{ - return a==b; -} - -// Resource type: NULL - -// Acquire resource i -void* -test_finalizer_acq_null_t(size_t i) -{ - gFinalizerTestResources[0] = 1;//Always index 0 - return NULL; -} - -// Release resource i -void -test_finalizer_rel_null_t(void *i) -{ - if (i != NULL) { - MOZ_NOT_REACHED("Assertion failed"); - } - gFinalizerTestResources[0] --; -} - -bool -test_finalizer_null_resource_is_acquired(size_t) -{ - return gFinalizerTestResources[0] == 1; -} - -bool -test_finalizer_cmp_null_t(void *a, void *b) -{ - return a==b; -} - -// Resource type: char* - -// Acquire resource i -char* -test_finalizer_acq_string_t(int i) -{ - gFinalizerTestResources[i] = 1; - if (!gFinalizerTestNames[i]) { - char* buf = new char[10]; - snprintf(buf, 10, "%d", i); - gFinalizerTestNames[i] = buf; - return buf; - } - return gFinalizerTestNames[i]; -} - -// Release resource i -void -test_finalizer_rel_string_t(char *i) -{ - int index = atoi(i); - if (index < 0 || index >= (int)gFinalizerTestSize) { - MOZ_NOT_REACHED("Assertion failed"); - } - gFinalizerTestResources[index] --; -} - -bool -test_finalizer_string_resource_is_acquired(size_t i) -{ - return gFinalizerTestResources[i] == 1; -} - -bool -test_finalizer_cmp_string_t(char *a, char *b) -{ - return !strncmp(a, b, 10); -} - -// Resource type: RECT - -// Acquire resource i -RECT -test_finalizer_acq_struct_t(int i) -{ - gFinalizerTestResources[i] = 1; - RECT result = { i, i, i, i }; - return result; -} - -// Release resource i -void -test_finalizer_rel_struct_t(RECT i) -{ - int index = i.top; - if (index < 0 || index >= (int)gFinalizerTestSize) { - MOZ_NOT_REACHED("Assertion failed"); - } - gFinalizerTestResources[index] --; -} - -bool -test_finalizer_struct_resource_is_acquired(RECT i) -{ - int index = i.top; - if (index < 0 || index >= (int)gFinalizerTestSize) { - MOZ_NOT_REACHED("Assertion failed"); - } - return gFinalizerTestResources[index] == 1; -} - -bool -test_finalizer_cmp_struct_t(RECT a, RECT b) -{ - return a.top == b.top; -} - -// Support for checking that we reject NULL finalizer -afun* test_finalizer_rel_null_function() -{ - return NULL; -} - -void -test_finalizer_rel_size_t_set_errno(size_t i) -{ - if (-- gFinalizerTestResources[i] < 0) { - MOZ_NOT_REACHED("Assertion failed"); - } - errno = 10; -} - -void -reset_errno() -{ - errno = 0; -} - diff --git a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.h b/toolkit/components/ctypes/tests/jsctypes-test-finalizer.h deleted file mode 100644 index cf3df010dea9..000000000000 --- a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jsapi.h" - -#define EXPORT_CDECL(type) NS_EXPORT type - -NS_EXTERN_C -{ - EXPORT_CDECL(void) test_finalizer_start(size_t size); - EXPORT_CDECL(void) test_finalizer_stop(); - EXPORT_CDECL(bool) test_finalizer_resource_is_acquired(size_t i); - - EXPORT_CDECL(size_t) test_finalizer_acq_size_t(size_t i); - EXPORT_CDECL(void) test_finalizer_rel_size_t(size_t i); - EXPORT_CDECL(size_t) test_finalizer_rel_size_t_return_size_t(size_t i); - EXPORT_CDECL(RECT) test_finalizer_rel_size_t_return_struct_t(size_t i); - EXPORT_CDECL(bool) test_finalizer_cmp_size_t(size_t a, size_t b); - - EXPORT_CDECL(int32_t) test_finalizer_acq_int32_t(size_t i); - EXPORT_CDECL(void) test_finalizer_rel_int32_t(int32_t i); - EXPORT_CDECL(bool) test_finalizer_cmp_int32_t(int32_t a, int32_t b); - - EXPORT_CDECL(int64_t) test_finalizer_acq_int64_t(size_t i); - EXPORT_CDECL(void) test_finalizer_rel_int64_t(int64_t i); - EXPORT_CDECL(bool) test_finalizer_cmp_int64_t(int64_t a, int64_t b); - - EXPORT_CDECL(void*) test_finalizer_acq_ptr_t(size_t i); - EXPORT_CDECL(void) test_finalizer_rel_ptr_t(void *i); - EXPORT_CDECL(bool) test_finalizer_cmp_ptr_t(void *a, void *b); - - EXPORT_CDECL(char*) test_finalizer_acq_string_t(int i); - EXPORT_CDECL(void) test_finalizer_rel_string_t(char *i); - EXPORT_CDECL(bool) test_finalizer_cmp_string_t(char *a, char *b); - - EXPORT_CDECL(void*) test_finalizer_acq_null_t(size_t i); - EXPORT_CDECL(void) test_finalizer_rel_null_t(void *i); - EXPORT_CDECL(bool) test_finalizer_cmp_null_t(void *a, void *b); - EXPORT_CDECL(bool) test_finalizer_null_resource_is_acquired(size_t i); - - EXPORT_CDECL(RECT) test_finalizer_acq_struct_t(int i); - EXPORT_CDECL(void) test_finalizer_rel_struct_t(RECT i); - EXPORT_CDECL(bool) test_finalizer_cmp_struct_t(RECT a, RECT b); - - typedef void (*afun)(size_t); - EXPORT_CDECL(afun*) test_finalizer_rel_null_function(); - - EXPORT_CDECL(void) test_finalizer_rel_size_t_set_errno(size_t i); - EXPORT_CDECL(void) reset_errno(); - -} diff --git a/toolkit/components/ctypes/tests/jsctypes-test.cpp b/toolkit/components/ctypes/tests/jsctypes-test.cpp index 8a9762d66abc..35051ac3f9a2 100644 --- a/toolkit/components/ctypes/tests/jsctypes-test.cpp +++ b/toolkit/components/ctypes/tests/jsctypes-test.cpp @@ -23,7 +23,6 @@ * Fredrik Larsson * Mark Finkle , * Dan Witte - * David Rajchenbach-Teller * * 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 @@ -40,15 +39,9 @@ * ***** END LICENSE BLOCK ***** */ #include "jsctypes-test.h" -#include "jsapi.h" #include "nsCRTGlue.h" #include #include -#include - -#if defined(XP_WIN) -#define snprintf _snprintf -#endif // defined(XP_WIN) template struct ValueTraits { static T literal() { return static_cast(109.25); } @@ -410,3 +403,4 @@ test_vector_add_va_cdecl(PRUint8 num_vecs, } RECT data_rect = { -1, -2, 3, 4 }; + diff --git a/toolkit/components/ctypes/tests/jsctypes-test.h b/toolkit/components/ctypes/tests/jsctypes-test.h index 2e84eba9ab04..25db4592269c 100644 --- a/toolkit/components/ctypes/tests/jsctypes-test.h +++ b/toolkit/components/ctypes/tests/jsctypes-test.h @@ -23,7 +23,6 @@ * Fredrik Larsson * Mark Finkle , * Dan Witte - * David Rajchenbach-Teller * * 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 diff --git a/toolkit/components/ctypes/tests/unit/head.js b/toolkit/components/ctypes/tests/unit/head.js index 04e79d9834be..a36f15d21790 100644 --- a/toolkit/components/ctypes/tests/unit/head.js +++ b/toolkit/components/ctypes/tests/unit/head.js @@ -77,18 +77,3 @@ function structural_check_eq_aux(a, b) { } ); } - -function trigger_gc() { - dump("Triggering garbage-collection"); - Components.utils.forceGC(); -} - -function must_throw(f) { - let has_thrown = false; - try { - f(); - } catch (x) { - has_thrown = true; - } - do_check_true(has_thrown); -} diff --git a/toolkit/components/ctypes/tests/unit/test_finalizer.js b/toolkit/components/ctypes/tests/unit/test_finalizer.js deleted file mode 100644 index d862d16de59c..000000000000 --- a/toolkit/components/ctypes/tests/unit/test_finalizer.js +++ /dev/null @@ -1,445 +0,0 @@ -let TEST_SIZE = 100; - -function run_test() -{ - let library = open_ctypes_test_lib(); - - let start = library.declare("test_finalizer_start", ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - let stop = library.declare("test_finalizer_stop", ctypes.default_abi, - ctypes.void_t); - let status = library.declare("test_finalizer_resource_is_acquired", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t); - let released = function(value, witness) { - return witness == undefined; - }; - - let samples = []; - samples.push( - { - name: "size_t", - acquire: library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_size_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.size_t), - compare: library.declare("test_finalizer_cmp_size_t", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t, - ctypes.size_t), - status: status, - released: released - }); - samples.push( - { - name: "size_t", - acquire: library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_size_t_set_errno", - ctypes.default_abi, - ctypes.void_t, - ctypes.size_t), - compare: library.declare("test_finalizer_cmp_size_t", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t, - ctypes.size_t), - status: status, - released: released - }); - samples.push( - { - name: "int32_t", - acquire: library.declare("test_finalizer_acq_int32_t", - ctypes.default_abi, - ctypes.int32_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_int32_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.int32_t), - compare: library.declare("test_finalizer_cmp_int32_t", - ctypes.default_abi, - ctypes.bool, - ctypes.int32_t, - ctypes.int32_t), - status: status, - released: released - } - ); - samples.push( - { - name: "int64_t", - acquire: library.declare("test_finalizer_acq_int64_t", - ctypes.default_abi, - ctypes.int64_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_int64_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.int64_t), - compare: library.declare("test_finalizer_cmp_int64_t", - ctypes.default_abi, - ctypes.bool, - ctypes.int64_t, - ctypes.int64_t), - status: status, - released: released - } - ); - samples.push( - { - name: "ptr", - acquire: library.declare("test_finalizer_acq_ptr_t", - ctypes.default_abi, - ctypes.PointerType(ctypes.void_t), - ctypes.size_t), - release: library.declare("test_finalizer_rel_ptr_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.PointerType(ctypes.void_t)), - compare: library.declare("test_finalizer_cmp_ptr_t", - ctypes.default_abi, - ctypes.bool, - ctypes.void_t.ptr, - ctypes.void_t.ptr), - status: status, - released: released - } - ); - samples.push( - { - name: "string", - acquire: library.declare("test_finalizer_acq_string_t", - ctypes.default_abi, - ctypes.char.ptr, - ctypes.int), - release: library.declare("test_finalizer_rel_string_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.char.ptr), - compare: library.declare("test_finalizer_cmp_string_t", - ctypes.default_abi, - ctypes.bool, - ctypes.char.ptr, - ctypes.char.ptr), - status: status, - released: released - } - ); - const rect_t = new ctypes.StructType("RECT", - [{ top : ctypes.int32_t }, - { left : ctypes.int32_t }, - { bottom: ctypes.int32_t }, - { right : ctypes.int32_t }]); - samples.push( - { - name: "struct", - acquire: library.declare("test_finalizer_acq_struct_t", - ctypes.default_abi, - rect_t, - ctypes.int), - release: library.declare("test_finalizer_rel_struct_t", - ctypes.default_abi, - ctypes.void_t, - rect_t), - compare: library.declare("test_finalizer_cmp_struct_t", - ctypes.default_abi, - ctypes.bool, - rect_t, - rect_t), - status: status, - released: released - } - ); - samples.push( - { - name: "size_t, release returns size_t", - acquire: library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_size_t_return_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t), - compare: library.declare("test_finalizer_cmp_size_t", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t, - ctypes.size_t), - status: status, - released: function(i, witness) { - return i == witness; - } - } - ); - samples.push( - { - name: "size_t, release returns RECT", - acquire: library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t), - release: library.declare("test_finalizer_rel_size_t_return_struct_t", - ctypes.default_abi, - rect_t, - ctypes.size_t), - compare: library.declare("test_finalizer_cmp_size_t", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t, - ctypes.size_t), - status: status, - released: function(i, witness) { - return witness.top == i - && witness.bottom == i - && witness.left == i - && witness.right == i; - } - } - ); - samples.push( - { - name: "using null", - acquire: library.declare("test_finalizer_acq_null_t", - ctypes.default_abi, - ctypes.PointerType(ctypes.void_t), - ctypes.size_t), - release: library.declare("test_finalizer_rel_null_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.PointerType(ctypes.void_t)), - status: library.declare("test_finalizer_null_resource_is_acquired", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t), - compare: library.declare("test_finalizer_cmp_null_t", - ctypes.default_abi, - ctypes.bool, - ctypes.void_t.ptr, - ctypes.void_t.ptr), - released: released - } - ); - - let tester = new ResourceTester(start, stop); - samples.forEach( - function(sample) { - dump("Executing finalization test for data "+sample.name+"\n"); - tester.launch(TEST_SIZE, test_executing_finalizers, sample); - tester.launch(TEST_SIZE, test_do_not_execute_finalizers_on_referenced_stuff, sample); - tester.launch(TEST_SIZE, test_executing_dispose, sample); - tester.launch(TEST_SIZE, test_executing_forget, sample); - tester.launch(TEST_SIZE, test_result_dispose, sample); - } - ); - - /* - * Following test deactivated: Cycle collection never takes place - * (see bug 727371) - tester.launch(TEST_SIZE, test_cycles, samples[0]); - */ - library.close(); -} - -// If only I could have Promises to test this :) -// There is only so much we can do at this stage, -// if we want to avoid tests overlapping. -function test_cycles(size, tc) { - // Now, restart this with unreferenced cycles - for (i = 0; i < size/2; ++i) { - let a = { - a: ctypes.CDataFinalizer(tc.acquire(i*2), tc.release), - b: { - b: ctypes.CDataFinalizer(tc.acquire(i*2+1), tc.release) - } - }; - a.b.a = a; - } - do_test_pending(); - - Components.utils.schedulePreciseGC( - function() { - // Check that _something_ has been finalized - do_check_true(count_finalized(size, tc) > 0); - do_test_finished(); - } - ); - - do_timeout(10000, do_throw); -} - - -function count_finalized(size, tc) { - let finalizedItems = 0; - for (let i = 0; i < size; ++i) { - if (!tc.status(i)) { - ++finalizedItems; - } - } - return finalizedItems; -} - -/** - * Test: - * - that (some) finalizers are executed; - * - that no finalizer is executed twice (this is done on the C side). - */ -function test_executing_finalizers(size, tc) -{ - dump("test_executing_finalizers\n"); - // Allocate |size| items without references - for (let i = 0; i < size; ++i) { - ctypes.CDataFinalizer(tc.acquire(i), tc.release); - } - trigger_gc(); // This should trigger some finalizations, hopefully all - - // Check that _something_ has been finalized - do_check_true(count_finalized(size, tc) > 0); -} - -/** - * Check that - * - |dispose| returns the proper result - */ -function test_result_dispose(size, tc) { - dump("test_result_dispose " + tc.name + "\n"); - let ref = []; - // Allocate |size| items with references - for (let i = 0; i < size; ++i) { - ref.push(ctypes.CDataFinalizer(tc.acquire(i), tc.release)); - } - do_check_eq(count_finalized(size, tc), 0); - - for (i = 0; i < size; ++i) { - let witness = ref[i].dispose(); - ref[i] = null; - if (!tc.released(i, witness)) { - do_check_true(tc.released(i, witness)); - } - } -} -/** - * Check that - * - |dispose| is executed properly - * - finalizers are not executed after |dispose| - */ -function test_executing_dispose(size, tc) -{ - dump("test_executing_dispose\n"); - let ref = []; - // Allocate |size| items with references - for (let i = 0; i < size; ++i) { - ref.push(ctypes.CDataFinalizer(tc.acquire(i), tc.release)); - } - do_check_eq(count_finalized(size, tc), 0); - - // Dispose of everything and make sure that everything has been cleaned up - ref.forEach( - function(v) { - v.dispose(); - } - ); - do_check_eq(count_finalized(size, tc), size); - - // Remove references - ref = []; - - // Re-acquireialize data and make sure that everything has been reinialized - for (i = 0; i < size; ++i) { - tc.acquire(i); - } - - do_check_eq(count_finalized(size, tc), 0); - - - // Attempt to trigger finalizations, ensure that they do not take place - trigger_gc(); - - do_check_eq(count_finalized(size, tc), 0); -} - - -/** - * Check that - * - |forget| does not dispose - * - |forget| has the right content - * - finalizers are not executed after |forget| - */ -function test_executing_forget(size, tc) -{ - dump("test_executing_forget\n"); - let ref = []; - // Allocate |size| items with references - for (let i = 0; i < size; ++i) { - let original = tc.acquire(i); - let finalizer = ctypes.CDataFinalizer(original, tc.release); - ref.push( - { - original: original, - finalizer: finalizer - } - ); - do_check_true(tc.compare(original, finalizer)); - } - do_check_eq(count_finalized(size, tc), 0); - - // Forget everything, making sure that we recover the original info - ref.forEach( - function(v) { - let original = v.original; - let recovered = v.finalizer.forget(); - // Note: Cannot use do_check_eq on Uint64 et al. - do_check_true(tc.compare(original, recovered)); - do_check_eq(original.constructor, recovered.constructor); - } - ); - - // Also make sure that we have not performed any clean up - do_check_eq(count_finalized(size, tc), 0); - - // Remove references - ref = []; - - // Attempt to trigger finalizations, ensure that they have no effect - trigger_gc(); - - do_check_eq(count_finalized(size, tc), 0); -} - - -/** - * Check that finalizers are not executed - */ -function test_do_not_execute_finalizers_on_referenced_stuff(size, tc) -{ - dump("test_do_not_execute_finalizers_on_referenced_stuff\n"); - - let ref = []; - // Allocate |size| items without references - for (let i = 0; i < size; ++i) { - ref.push(ctypes.CDataFinalizer(tc.acquire(i), tc.release)); - } - trigger_gc(); // This might trigger some finalizations, but it should not - - // Check that _nothing_ has been finalized - do_check_eq(count_finalized(size, tc), 0); - - // Clean up manually, lest leftover data interferes with following tests - ref.forEach(function(v) { - v.dispose(); - }); - ref = []; - trigger_gc(); -} - diff --git a/toolkit/components/ctypes/tests/unit/test_finalizer_shouldaccept.js b/toolkit/components/ctypes/tests/unit/test_finalizer_shouldaccept.js deleted file mode 100644 index 163d8d604189..000000000000 --- a/toolkit/components/ctypes/tests/unit/test_finalizer_shouldaccept.js +++ /dev/null @@ -1,122 +0,0 @@ -try { - // We might be running without privileges, in which case it's up to the - // harness to give us the 'ctypes' object. - Components.utils.import("resource://gre/modules/ctypes.jsm"); -} catch(e) { -} - -let acquire, dispose, reset_errno, dispose_errno; - -function run_test() -{ - let library = open_ctypes_test_lib(); - - let start = library.declare("test_finalizer_start", ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - let stop = library.declare("test_finalizer_stop", ctypes.default_abi, - ctypes.void_t); - let tester = new ResourceTester(start, stop); - acquire = library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t); - dispose = library.declare("test_finalizer_rel_size_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - reset_errno = library.declare("reset_errno", - ctypes.default_abi, - ctypes.void_t); - dispose_errno = library.declare("test_finalizer_rel_size_t_set_errno", - ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - tester.launch(10, test_to_string); - tester.launch(10, test_to_source); - tester.launch(10, test_to_int); - tester.launch(10, test_errno); -} - -/** - * Check that toString succeeds before/after forget/dispose. - */ -function test_to_string() -{ - do_print("Starting test_to_string"); - let a = ctypes.CDataFinalizer(acquire(0), dispose); - do_check_eq(a.toString(), "0"); - - a.forget(); - do_check_eq(a.toString(), "[CDataFinalizer - empty]"); - - a = ctypes.CDataFinalizer(acquire(0), dispose); - a.dispose(); - do_check_eq(a.toString(), "[CDataFinalizer - empty]"); -} - -/** - * Check that toSource succeeds before/after forget/dispose. - */ -function test_to_source() -{ - do_print("Starting test_to_source"); - let value = acquire(0); - let a = ctypes.CDataFinalizer(value, dispose); - do_check_eq(a.toSource(), - "ctypes.CDataFinalizer(" - + ctypes.size_t(value).toSource() - +", " - +dispose.toSource() - +")"); - value = null; - - a.forget(); - do_check_eq(a.toSource(), "ctypes.CDataFinalizer()"); - - a = ctypes.CDataFinalizer(acquire(0), dispose); - a.dispose(); - do_check_eq(a.toSource(), "ctypes.CDataFinalizer()"); -} - -/** - * Test conversion to int32 - */ -function test_to_int() -{ - let value = 2; - let wrapped, converted, finalizable; - wrapped = ctypes.int32_t(value); - finalizable= ctypes.CDataFinalizer(acquire(value), dispose); - converted = ctypes.int32_t(finalizable); - - structural_check_eq(converted, wrapped); - structural_check_eq(converted, ctypes.int32_t(finalizable.forget())); - - wrapped = ctypes.int64_t(value); - converted = ctypes.int64_t(ctypes.CDataFinalizer(acquire(value), - dispose)); - structural_check_eq(converted, wrapped); -} - -/** - * Test that dispose can change errno but finalization cannot - */ -function test_errno(size) -{ - reset_errno(); - do_check_eq(ctypes.errno, 0); - - let finalizable = ctypes.CDataFinalizer(acquire(3), dispose_errno); - finalizable.dispose(); - do_check_eq(ctypes.errno, 10); - reset_errno(); - - do_check_eq(ctypes.errno, 0); - for (let i = 0; i < size; ++i) { - finalizable = ctypes.CDataFinalizer(acquire(i), dispose_errno); - } - - trigger_gc(); - do_check_eq(ctypes.errno, 0); -} \ No newline at end of file diff --git a/toolkit/components/ctypes/tests/unit/test_finalizer_shouldfail.js b/toolkit/components/ctypes/tests/unit/test_finalizer_shouldfail.js deleted file mode 100644 index fb14a674839c..000000000000 --- a/toolkit/components/ctypes/tests/unit/test_finalizer_shouldfail.js +++ /dev/null @@ -1,156 +0,0 @@ -try { - // We might be running without privileges, in which case it's up to the - // harness to give us the 'ctypes' object. - Components.utils.import("resource://gre/modules/ctypes.jsm"); -} catch(e) { -} - -let acquire, dispose, null_dispose, compare; - -function run_test() -{ - let library = open_ctypes_test_lib(); - - let start = library.declare("test_finalizer_start", ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - let stop = library.declare("test_finalizer_stop", ctypes.default_abi, - ctypes.void_t); - let tester = new ResourceTester(start, stop); - acquire = library.declare("test_finalizer_acq_size_t", - ctypes.default_abi, - ctypes.size_t, - ctypes.size_t); - dispose = library.declare("test_finalizer_rel_size_t", - ctypes.default_abi, - ctypes.void_t, - ctypes.size_t); - compare = library.declare("test_finalizer_cmp_size_t", - ctypes.default_abi, - ctypes.bool, - ctypes.size_t, - ctypes.size_t); - - let type_afun = ctypes.FunctionType(ctypes.default_abi, - ctypes.void_t, - [ctypes.size_t]).ptr; - - let null_dispose_maker = - library.declare("test_finalizer_rel_null_function", - ctypes.default_abi, - type_afun - ); - null_dispose = null_dispose_maker(); - - tester.launch(10, test_double_dispose); - tester.launch(10, test_finalize_bad_construction); - tester.launch(10, test_null_dispose); - tester.launch(10, test_pass_disposed); -} - - -/** - * Testing construction of finalizers with wrong arguments. - */ -function test_finalize_bad_construction() { - // First argument does not match second - must_throw(function() { ctypes.CDataFinalizer({}, dispose); }); - must_throw(function() { ctypes.CDataFinalizer(dispose, dispose); }); - - // Not enough arguments - must_throw(function() { ctypes.CDataFinalizer(init(0)); }); - - // Too many arguments - must_throw(function() { ctypes.CDataFinalizer(init(0), dispose, dispose); }); - - // Second argument is null - must_throw(function() { ctypes.CDataFinalizer(init(0), null); }); - - // Second argument is undefined - must_throw(function() { - let a; - ctypes.CDataFinalizer(init(0), a); - }); - -} - -/** - * Test that forget/dispose can only take place once. - */ -function test_double_dispose() { - function test_one_combination(i, a, b) { - let v = ctypes.CDataFinalizer(acquire(i), dispose); - a(v); - must_throw(function() { b(v); } ); - } - - let call_dispose = function(v) { - v.dispose(); - }; - let call_forget = function(v) { - v.forget(); - }; - - test_one_combination(0, call_dispose, call_dispose); - test_one_combination(1, call_dispose, call_forget); - test_one_combination(2, call_forget, call_dispose); - test_one_combination(3, call_forget, call_forget); -} - - -/** - * Test that nothing (too) bad happens when the finalizer is NULL - */ -function test_null_dispose() -{ - let exception; - - exception = false; - try { - let v = ctypes.CDataFinalizer(acquire(0), null_dispose); - } catch (x) { - exception = true; - } - do_check_true(exception); -} - -/** - * Test that conversion of a disposed/forgotten CDataFinalizer to a C - * value fails nicely. - */ -function test_pass_disposed() -{ - let exception, v; - - exception = false; - v = ctypes.CDataFinalizer(acquire(0), dispose); - do_check_true(compare(v, 0)); - v.forget(); - - try { - compare(v, 0); - } catch (x) { - exception = true; - } - do_check_true(exception); - - exception = false; - v = ctypes.CDataFinalizer(acquire(0), dispose); - do_check_true(compare(v, 0)); - v.dispose(); - - try { - compare(v, 0); - } catch (x) { - exception = true; - } - do_check_true(exception); - - exception = false; - try { - ctypes.int32_t(ctypes.CDataFinalizer(v, dispose)); - } catch (x) { - exception = true; - } - do_check_true(exception); -} \ No newline at end of file diff --git a/toolkit/components/ctypes/tests/unit/xpcshell.ini b/toolkit/components/ctypes/tests/unit/xpcshell.ini index 50451571aec7..a70757a0cc12 100644 --- a/toolkit/components/ctypes/tests/unit/xpcshell.ini +++ b/toolkit/components/ctypes/tests/unit/xpcshell.ini @@ -4,10 +4,6 @@ tail = [test_errno.js] -[test_finalizer.js] -[test_finalizer_shouldfail.js] -[test_finalizer_shouldaccept.js] - [test_jsctypes.js] # Bug 676989: test fails consistently on Android fail-if = os == "android"