From 2626e52ff3ca708e6c76d7044dc1cba2110beba2 Mon Sep 17 00:00:00 2001 From: Dan Witte Date: Thu, 11 Mar 2010 17:17:36 -0800 Subject: [PATCH] Revise js-facing API for js-ctypes, patch v3. b=513788, r=jorendorff --- js/ctypes/CTypes.cpp | 277 ++++++++++++----------- js/ctypes/CTypes.h | 6 +- js/ctypes/Library.cpp | 2 +- js/ctypes/tests/unit/test_jsctypes.js.in | 2 +- 4 files changed, 150 insertions(+), 137 deletions(-) diff --git a/js/ctypes/CTypes.cpp b/js/ctypes/CTypes.cpp index f9d706cc1da9..57f548d487b2 100644 --- a/js/ctypes/CTypes.cpp +++ b/js/ctypes/CTypes.cpp @@ -36,13 +36,13 @@ * * ***** END LICENSE BLOCK ***** */ +#include "jscntxt.h" #include "CTypes.h" #include "nsAutoPtr.h" #include "nsUTF8Utils.h" #include "nsCRTGlue.h" #include "prlog.h" #include "prdtoa.h" -#include "jscntxt.h" #include "jsnum.h" namespace mozilla { @@ -100,7 +100,7 @@ static JSPropertySpec sCTypeProps[] = { { "name", 0, CTYPESPROP_FLAGS, CType::NameGetter, NULL }, { "size", 0, CTYPESPROP_FLAGS, CType::SizeGetter, NULL }, { "ptr", 0, CTYPESPROP_FLAGS, CType::PtrGetter, NULL }, - { "prototype", 0, CTYPESPROP_FLAGS, CType::ProtoGetter, NULL }, + { "prototype", 0, CTYPESPROP_FLAGS, CType::PrototypeGetter, NULL }, { 0, 0, 0, NULL, NULL } }; @@ -123,7 +123,7 @@ static JSFunctionSpec sPointerFunction = JS_FN("PointerType", PointerType::Create, 1, CTYPESFN_FLAGS); static JSPropertySpec sPointerProps[] = { - { "targetType", 0, CTYPESPROP_FLAGS, PointerType::TargetGetter, NULL }, + { "targetType", 0, CTYPESPROP_FLAGS, PointerType::TargetTypeGetter, NULL }, { 0, 0, 0, NULL, NULL } }; @@ -230,6 +230,20 @@ static JSFunctionSpec sUInt64Functions[] = { JS_FS_END }; +JS_ALWAYS_INLINE void +ASSERT_OK(JSBool ok) +{ + JS_ASSERT(ok); +} + +JS_ALWAYS_INLINE JSString* +NewUCString(JSContext* cx, const nsString& from) +{ + JS_ASSERT(from.get()); + return JS_NewUCStringCopyN(cx, + reinterpret_cast(from.get()), from.Length()); +} + ABICode GetABICode(JSContext* cx, JSObject* obj) { @@ -239,7 +253,7 @@ GetABICode(JSContext* cx, JSObject* obj) return INVALID_ABI; jsval result; - JS_GetReservedSlot(cx, obj, SLOT_ABICODE, &result); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ABICODE, &result)); return ABICode(JSVAL_TO_INT(result)); } @@ -360,7 +374,7 @@ InitInt64Class(JSContext* cx, // Stash ctypes.{Int64,UInt64}.prototype on a reserved slot of the 'join' // function. jsval join; - JS_GetProperty(cx, ctor, "join", &join); + ASSERT_OK(JS_GetProperty(cx, ctor, "join", &join)); if (!JS_SetReservedSlot(cx, JSVAL_TO_OBJECT(join), SLOT_FN_INT64PROTO, OBJECT_TO_JSVAL(prototype))) return NULL; @@ -374,7 +388,7 @@ InitInt64Class(JSContext* cx, static JSBool AttachProtos(JSContext* cx, JSObject* proto, JSObject** protos) { - // For a given 'proto' of class [[CTypeProto]], attach each of the 'protos' + // For a given 'proto' of [[Class]] CTypeProto, attach each of the 'protos' // to the appropriate CTypeProtoSlot. for (PRUint32 i = 0; i < CTYPEPROTO_SLOTS; ++i) { if (!JS_SetReservedSlot(cx, proto, i, OBJECT_TO_JSVAL(protos[i]))) @@ -389,12 +403,12 @@ InitTypeClasses(JSContext* cx, JSObject* parent) { // Initialize the ctypes.CType class. This acts as an abstract base class for // the various types, and provides the common API functions. It has: - // * Class [[Function]] + // * [[Class]] "Function" // * __proto__ === Function.prototype // * A constructor that throws a TypeError. (You can't construct an // abstract type!) // * 'prototype' property: - // * Class [[CTypeProto]] + // * [[Class]] "CTypeProto" // * __proto__ === Function.prototype === ctypes.CType.__proto__ // * 'constructor' property === ctypes.CType JSObject* CTypeProto = JS_InitClass(cx, parent, NULL, &sCTypeProtoClass, @@ -428,12 +442,12 @@ InitTypeClasses(JSContext* cx, JSObject* parent) // Create objects representing the builtin types, and attach them to the // ctypes object. Each type object 't' has: - // * Class [[CType]] + // * [[Class]] "CType" // * __proto__ === ctypes.CType.prototype // * A constructor which creates and returns a CData object, containing // binary data of the given type. // * 'prototype' property: - // * Class [[Object]] + // * [[Class]] "Object" // * __proto__ === Object.prototype // * 'constructor' property === 't' #define DEFINE_TYPE(name, type, ffiType) \ @@ -454,11 +468,11 @@ InitTypeClasses(JSContext* cx, JSObject* parent) // Create and attach the special class constructors: // ctypes.PointerType, ctypes.ArrayType, and ctypes.StructType. // Each of these has, respectively: - // * Class [[Function]] + // * [[Class]] "Function" // * __proto__ === Function.prototype // * A constructor that creates a user-defined type. // * 'prototype' property: - // * Class [[CTypeProto]] + // * [[Class]] "CTypeProto" // * __proto__ === ctypes.CType.prototype // * 'constructor' property === ctypes.{Pointer,Array,Struct}Type JSObject* protos[CTYPEPROTO_SLOTS]; @@ -477,10 +491,10 @@ InitTypeClasses(JSContext* cx, JSObject* parent) // Create and attach the ctypes.{Int64,UInt64} constructors. // Each of these has, respectively: - // * Class [[Function]] + // * [[Class]] "Function" // * A constructor that creates a ctypes.{Int64,UInt64} object, respectively. // * 'prototype' property: - // * Class [[{Int64Proto,UInt64Proto}]] + // * [[Class]] {"Int64Proto","UInt64Proto"} // * __proto__ === Function.prototype === ctypes.{Int64,UInt64}.__proto__ // * 'constructor' property === ctypes.{Int64,UInt64} protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass, @@ -496,12 +510,12 @@ InitTypeClasses(JSContext* cx, JSObject* parent) // the special type constructors, and Int64/UInt64 types, so we can access // them when constructing instances of those types. An instance 't' of // ctypes.{Pointer,Array,Struct}Type will have, resp.: - // * Class [[CType]] + // * [[Class]] "CType" // * __proto__ === ctypes.{Pointer,Array,Struct}Type.prototype // * A constructor which creates and returns a CData object, containing // binary data of the given type. // * 'prototype' property: - // * Class [[Object]] + // * [[Class]] "Object" // * __proto__ === Object.prototype // * 'constructor' property === t if (!AttachProtos(cx, CTypeProto, protos) || @@ -544,6 +558,7 @@ PR_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8); PR_STATIC_ASSERT(sizeof(long long) == 8); PR_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t)); PR_STATIC_ASSERT(sizeof(float) == 4); +PR_STATIC_ASSERT(sizeof(jschar) == sizeof(PRUnichar)); template static JS_ALWAYS_INLINE IntegerType @@ -605,7 +620,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result) if (JSVAL_IS_DOUBLE(val)) { jsdouble d = *JSVAL_TO_DOUBLE(val); *result = d != 0; - // Disallow -0. + // Allow -0. return d == 1 || d == 0; } // Don't silently convert null to bool. It's probably a mistake. @@ -1108,7 +1123,7 @@ ConvertToJS(JSContext* cx, } #define DEFINE_CHAR_TYPE(name, type, ffiType) \ case TYPE_##name: \ - /* Convert to an integer. (We have no idea what character encoding to */ \ + /* Convert to an integer. We have no idea what character encoding to */ \ /* use, if any. */ \ *result = INT_TO_JSVAL(*static_cast(data)); \ break; @@ -1217,14 +1232,13 @@ ImplicitConvert(JSContext* cx, case TYPE_##name: { \ /* Convert from a 1-character string, regardless of encoding, */ \ /* or from an integer, provided the result fits in 'type'. */ \ - /* TODO: Check IsASCII(chars) for 8-bit char types? */ \ type result; \ if (JSVAL_IS_STRING(val)) { \ JSString* str = JSVAL_TO_STRING(val); \ if (JS_GetStringLength(str) != 1) \ return TypeError(cx, #name, val); \ \ - jschar c = *JS_GetStringCharsZ(cx, str); \ + jschar c = *JS_GetStringChars(str); \ result = c; \ if (jschar(result) != c) \ return TypeError(cx, #name, val); \ @@ -1513,7 +1527,7 @@ ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer) case TYPE_bool: { // Convert according to the ECMAScript ToBoolean() function. JSBool result; - JS_ValueToBoolean(cx, val, &result); + ASSERT_OK(JS_ValueToBoolean(cx, val, &result)); *static_cast(buffer) = result != JS_FALSE; break; } @@ -1780,8 +1794,22 @@ BuildDataSource(JSContext* cx, JSObject* typeObj, void* data, bool isImplicit) /* Serialize as an integer. */ \ result.Append(IntegerToString(*static_cast(data), 10)); \ break; -#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z) #include "typedefs.h" + case TYPE_jschar: { + /* Serialize as a 1-character JS string. */ + JSString* str = JS_NewUCStringCopyN(cx, static_cast(data), 1); + if (!str) + break; + + JSString* src = JS_ValueToSource(cx, STRING_TO_JSVAL(str)); + if (!src) + break; + + const jschar* srcChars = JS_GetStringChars(src); + size_t srclen = JS_GetStringLength(src); + result.Append(reinterpret_cast(srcChars), srclen); + break; + } case TYPE_pointer: { if (isImplicit) { // The result must be able to ImplicitConvert successfully. @@ -1889,7 +1917,7 @@ CType::ConstructData(JSContext* cx, // How we construct the CData object depends on what type we represent. // An instance 'd' of a CData object of type 't' has: - // * Class [[CData]] + // * [[Class]] "CData" // * __proto__ === t.prototype switch (GetTypeCode(cx, obj)) { case TYPE_void_t: @@ -1946,13 +1974,13 @@ CType::Create(JSContext* cx, { // Create a CType object with the properties and slots common to all CTypes. // Each type object 't' has: - // * Class [[CType]] + // * [[Class]] "CType" // * __proto__ === 'proto'; one of ctypes.{CType,PointerType,ArrayType, // StructType}.prototype // * A constructor which creates and returns a CData object, containing // binary data of the given type. // * 'prototype' property: - // * Class [[Object]] + // * [[Class]] "Object" // * __proto__ === Object.prototype // * 'constructor' property === 't' JSObject* typeObj = JS_NewObject(cx, &sCTypeClass, proto, NULL); @@ -2053,7 +2081,7 @@ CType::Finalize(JSContext* cx, JSObject* obj) switch (TypeCode(JSVAL_TO_INT(slot))) { case TYPE_struct: // Free the FieldInfo array. - JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); if (!JSVAL_IS_VOID(slot)) delete static_cast*>(JSVAL_TO_PRIVATE(slot)); @@ -2061,7 +2089,7 @@ CType::Finalize(JSContext* cx, JSObject* obj) case TYPE_array: { // Free the ffi_type info. jsval slot; - JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot)); if (!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot)) { ffi_type* ffiType = static_cast(JSVAL_TO_PRIVATE(slot)); delete[] ffiType->elements; @@ -2088,7 +2116,7 @@ CType::GetTypeCode(JSContext* cx, JSObject* typeObj) JS_ASSERT(IsCType(cx, typeObj)); jsval result; - JS_GetReservedSlot(cx, typeObj, SLOT_TYPECODE, &result); + ASSERT_OK(JS_GetReservedSlot(cx, typeObj, SLOT_TYPECODE, &result)); return TypeCode(JSVAL_TO_INT(result)); } @@ -2148,7 +2176,7 @@ CType::GetSafeSize(JSContext* cx, JSObject* obj, size_t* result) JS_ASSERT(CType::IsCType(cx, obj)); jsval size; - JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. @@ -2171,7 +2199,7 @@ CType::GetSize(JSContext* cx, JSObject* obj) JS_ASSERT(CType::IsCType(cx, obj)); jsval size; - JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); JS_ASSERT(!JSVAL_IS_VOID(size)); @@ -2189,7 +2217,7 @@ CType::IsSizeDefined(JSContext* cx, JSObject* obj) JS_ASSERT(CType::IsCType(cx, obj)); jsval size; - JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. @@ -2203,7 +2231,7 @@ CType::GetAlignment(JSContext* cx, JSObject* obj) JS_ASSERT(CType::IsCType(cx, obj)); jsval slot; - JS_GetReservedSlot(cx, obj, SLOT_ALIGN, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ALIGN, &slot)); return static_cast(JSVAL_TO_INT(slot)); } @@ -2213,7 +2241,7 @@ CType::GetFFIType(JSContext* cx, JSObject* obj) JS_ASSERT(CType::IsCType(cx, obj)); jsval slot; - JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot)); ffi_type* result = static_cast(JSVAL_TO_PRIVATE(slot)); JS_ASSERT(result); @@ -2226,24 +2254,22 @@ CType::GetName(JSContext* cx, JSObject* obj) JS_ASSERT(CType::IsCType(cx, obj)); jsval string; - JS_GetReservedSlot(cx, obj, SLOT_NAME, &string); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_NAME, &string)); return JSVAL_TO_STRING(string); } JSObject* -CType::GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot) +CType::GetProtoFromCtor(JSContext* cx, JSObject* obj) { // Look at the 'prototype' property of the type constructor. jsval prototype; - JS_GetProperty(cx, obj, "prototype", &prototype); + ASSERT_OK(JS_GetProperty(cx, obj, "prototype", &prototype)); JSObject* proto = JSVAL_TO_OBJECT(prototype); JS_ASSERT(proto); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sCTypeProtoClass); - // Get the requested ctypes.{Pointer,Array,Struct}Type.prototype. - jsval result; - JS_GetReservedSlot(cx, proto, slot, &result); - return JSVAL_TO_OBJECT(result); + // Return the desired ctypes.{Pointer,Array,Struct}Type.prototype. + return proto; } JSObject* @@ -2258,19 +2284,19 @@ CType::GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot) // Get the requested ctypes.{Pointer,Array,Struct}Type.prototype. jsval result; - JS_GetReservedSlot(cx, proto, slot, &result); + ASSERT_OK(JS_GetReservedSlot(cx, proto, slot, &result)); return JSVAL_TO_OBJECT(result); } JSBool -CType::ProtoGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) { if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_PROTO, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_PROTO, vp)); JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); return JS_TRUE; } @@ -2283,7 +2309,7 @@ CType::NameGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_NAME, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_NAME, vp)); JS_ASSERT(JSVAL_IS_STRING(*vp)); return JS_TRUE; } @@ -2296,7 +2322,7 @@ CType::SizeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_SIZE, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, vp)); JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp)); return JS_TRUE; } @@ -2367,8 +2393,7 @@ CType::ToString(JSContext* cx, uintN argc, jsval *vp) size_t rightlen = JS_GetStringLength(right); type.Append(reinterpret_cast(rightChars), rightlen); - JSString* result = JS_NewUCStringCopyN(cx, - reinterpret_cast(type.get()), type.Length()); + JSString* result = NewUCString(cx, type); if (!result) return JS_FALSE; @@ -2388,8 +2413,7 @@ CType::ToSource(JSContext* cx, uintN argc, jsval *vp) } nsAutoString source = BuildTypeSource(cx, obj, false); - JSString* result = JS_NewUCStringCopyN(cx, - reinterpret_cast(source.get()), source.Length()); + JSString* result = NewUCString(cx, source); if (!result) return JS_FALSE; @@ -2447,7 +2471,7 @@ PointerType::CreateInternal(JSContext* cx, if (baseType) { // check if we have a cached PointerType on our base CType. jsval slot; - JS_GetReservedSlot(cx, baseType, SLOT_PTR, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, baseType, SLOT_PTR, &slot)); if (!JSVAL_IS_VOID(slot)) return JSVAL_TO_OBJECT(slot); } @@ -2456,7 +2480,7 @@ PointerType::CreateInternal(JSContext* cx, // whichever was provided. JSObject* proto; if (ctor) - proto = CType::GetProtoFromCtor(cx, ctor, SLOT_POINTERPROTO); + proto = CType::GetProtoFromCtor(cx, ctor); else proto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO); @@ -2477,8 +2501,7 @@ PointerType::CreateInternal(JSContext* cx, if (baseType) { // Determine the name of the PointerType, since it wasn't supplied. nsAutoString typeName = BuildTypeName(cx, typeObj); - JSString* nameStr = JS_NewUCStringCopyN(cx, - reinterpret_cast(typeName.get()), typeName.Length()); + JSString* nameStr = NewUCString(cx, typeName); if (!nameStr || !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(nameStr))) return NULL; @@ -2528,19 +2551,22 @@ PointerType::GetBaseType(JSContext* cx, JSObject* obj) JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_pointer); jsval type; - JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, &type); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, &type)); return JSVAL_TO_OBJECT(type); } JSBool -PointerType::TargetGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +PointerType::TargetTypeGetter(JSContext* cx, + JSObject* obj, + jsval idval, + jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_pointer) { JS_ReportError(cx, "not a PointerType"); return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, vp)); JS_ASSERT(JSVAL_IS_OBJECT(*vp)); return JS_TRUE; } @@ -2746,8 +2772,7 @@ ArrayType::CreateInternal(JSContext* cx, // Determine the name of the ArrayType. nsAutoString typeName = BuildTypeName(cx, typeObj); - JSString* name = JS_NewUCStringCopyN(cx, - reinterpret_cast(typeName.get()), typeName.Length()); + JSString* name = NewUCString(cx, typeName); if (!name || !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(name))) return NULL; @@ -2866,7 +2891,7 @@ ArrayType::GetBaseType(JSContext* cx, JSObject* obj) JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); jsval type; - JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, &type); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, &type)); return JSVAL_TO_OBJECT(type); } @@ -2877,7 +2902,7 @@ ArrayType::GetSafeLength(JSContext* cx, JSObject* obj, size_t* result) JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); jsval length; - JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length)); // The "length" property can be a jsint, a jsdouble, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. @@ -2901,7 +2926,7 @@ ArrayType::GetLength(JSContext* cx, JSObject* obj) JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); jsval length; - JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length)); JS_ASSERT(!JSVAL_IS_VOID(length)); @@ -2921,7 +2946,7 @@ ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, vp)); JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); return JS_TRUE; } @@ -2939,7 +2964,7 @@ ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_LENGTH, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, vp)); JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp)); return JS_TRUE; } @@ -3088,10 +3113,6 @@ ExtractStructField(JSContext* cx, jsval val, FieldInfo* field) jsid id; if (!JS_NextProperty(cx, iter, &id)) return false; - if (JSVAL_IS_VOID(id)) { - JS_ReportError(cx, "struct field descriptors require a valid name and type"); - return false; - } jsval nameVal; if (!JS_IdToValue(cx, id, &nameVal)) @@ -3193,7 +3214,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) // Process the field types and fill in the ffi_type fields. JSObject* fieldsObj = JSVAL_TO_OBJECT(argv[1]); jsuint len; - JS_GetArrayLength(cx, fieldsObj, &len); + ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len)); nsAutoPtr ffiType(new ffi_type); if (!ffiType) { @@ -3325,7 +3346,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) // Get ctypes.StructType.prototype from the ctypes.StructType constructor. JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); - JSObject* proto = CType::GetProtoFromCtor(cx, callee, SLOT_STRUCTPROTO); + JSObject* proto = CType::GetProtoFromCtor(cx, callee); // Create a new CType object with the common properties and slots. JSObject* typeObj = CType::Create(cx, proto, TYPE_struct, name, @@ -3371,61 +3392,56 @@ StructType::ConstructData(JSContext* cx, *rval = OBJECT_TO_JSVAL(result); - if (argc != 0) { - char* buffer = static_cast(CData::GetData(cx, result)); - nsTArray* fields = GetFieldInfo(cx, obj); + if (argc == 0) + return JS_TRUE; - if (argc == 1) { - // There are two possible interpretations of the argument: - // 1) It may be an object '{ ... }' with properties representing the - // struct fields intended to ExplicitConvert wholesale to our StructType. - // 2) If the struct contains one field, the arg may be intended to - // ImplicitConvert directly to that arg's CType. - // Thankfully, the conditions for these two possibilities to succeed - // are mutually exclusive, so we can pick the right one. + char* buffer = static_cast(CData::GetData(cx, result)); + nsTArray* fields = GetFieldInfo(cx, obj); - // Try option 1) first. - if (ExplicitConvert(cx, argv[0], obj, buffer)) - return JS_TRUE; + if (argc == 1) { + // There are two possible interpretations of the argument: + // 1) It may be an object '{ ... }' with properties representing the + // struct fields intended to ExplicitConvert wholesale to our StructType. + // 2) If the struct contains one field, the arg may be intended to + // ImplicitConvert directly to that arg's CType. + // Thankfully, the conditions for these two possibilities to succeed + // are mutually exclusive, so we can pick the right one. - // If ExplicitConvert failed, and there is no pending exception, then assume - // hard failure (out of memory, or some other similarly serious condition). - if (!JS_IsExceptionPending(cx)) - return JS_FALSE; + // Try option 1) first. + if (ExplicitConvert(cx, argv[0], obj, buffer)) + return JS_TRUE; - // Otherwise, assume soft failure, and clear the pending exception so that we - // can throw a different one as required. - JS_ClearPendingException(cx); - - if (fields->Length() != 1) { - JS_ReportError(cx, "constructor takes 0, 1, or %u arguments", - fields->Length()); - return JS_FALSE; - } - - // Try option 2). - FieldInfo& field = fields->ElementAt(0); - return ImplicitConvert(cx, argv[0], field.mType, buffer + field.mOffset, - false, NULL); - } - - if (argc != fields->Length()) { - JS_ReportError(cx, "constructor takes 0, 1, or %u arguments", - fields->Length()); + if (fields->Length() != 1) return JS_FALSE; - } - // Otherwise, we have a type constructor of the form - // 'ctypes.StructType(a, b, c, ...)'. ImplicitConvert each field. + // If ExplicitConvert failed, and there is no pending exception, then assume + // hard failure (out of memory, or some other similarly serious condition). + if (!JS_IsExceptionPending(cx)) + return JS_FALSE; + + // Otherwise, assume soft failure, and clear the pending exception so that we + // can throw a different one as required. + JS_ClearPendingException(cx); + + // Fall through to try option 2). + } + + // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'. + // ImplicitConvert each field. + if (argc == fields->Length()) { for (PRUint32 i = 0; i < fields->Length(); ++i) { FieldInfo& field = fields->ElementAt(i); if (!ImplicitConvert(cx, argv[i], field.mType, buffer + field.mOffset, false, NULL)) return JS_FALSE; } + + return JS_TRUE; } - return JS_TRUE; + JS_ReportError(cx, "constructor takes 0, 1, or %u arguments", + fields->Length()); + return JS_FALSE; } nsTArray* @@ -3435,7 +3451,7 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj) JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); jsval slot; - JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot)); return static_cast*>(JSVAL_TO_PRIVATE(slot)); @@ -3473,7 +3489,7 @@ StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* return JS_FALSE; } - JS_GetReservedSlot(cx, obj, SLOT_FIELDS, vp); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDS, vp)); JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*vp))); return JS_TRUE; @@ -3575,11 +3591,11 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval *vp) // Create a new CData object of type 'typeObj' containing binary data supplied // in 'source', optionally with a referent CData object 'baseObj'. // * 'typeObj' must be a CType of defined (but possibly zero) size. -// * If a CData object 'parentObj' is supplied, the new CData object becomes +// * If a CData object 'baseObj' is supplied, the new CData object becomes // dependent on the given parent and its buffer refers to a slice of the -// parent's buffer, supplied in 'source'. 'parentObj' will be held alive by +// parent's buffer, supplied in 'source'. 'baseObj' will be held alive by // the resulting CData object. -// * If 'parentObj' is null, the new CData object will create a new buffer of +// * If 'baseObj' is null, the new CData object will create a new buffer of // size given by 'typeObj'. If 'source' data is supplied, the data will be // copied from 'source' into the new buffer; otherwise, the entirety of the // new buffer will be initialized to zero. @@ -3594,7 +3610,7 @@ CData::Create(JSContext* cx, JSObject* typeObj, JSObject* baseObj, void* source) // Get the 'prototype' property from the type. jsval slot; - JS_GetReservedSlot(cx, typeObj, SLOT_PROTO, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, typeObj, SLOT_PROTO, &slot)); JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); @@ -3674,7 +3690,7 @@ CData::GetCType(JSContext* cx, JSObject* dataObj) JS_ASSERT(CData::IsCData(cx, dataObj)); jsval slot; - JS_GetReservedSlot(cx, dataObj, SLOT_CTYPE, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, dataObj, SLOT_CTYPE, &slot)); JSObject* typeObj = JSVAL_TO_OBJECT(slot); JS_ASSERT(CType::IsCType(cx, typeObj)); return typeObj; @@ -3686,7 +3702,7 @@ CData::GetData(JSContext* cx, JSObject* dataObj) JS_ASSERT(CData::IsCData(cx, dataObj)); jsval slot; - JS_GetReservedSlot(cx, dataObj, SLOT_DATA, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, dataObj, SLOT_DATA, &slot)); void** buffer = static_cast(JSVAL_TO_PRIVATE(slot)); JS_ASSERT(buffer); @@ -3868,9 +3884,7 @@ CData::ReadString(JSContext* cx, uintN argc, jsval *vp) return JS_FALSE; } - NS_ConvertUTF8toUTF16 converted(string); - result = JS_NewUCStringCopyN(cx, - reinterpret_cast(converted.get()), converted.Length()); + result = NewUCString(cx, NS_ConvertUTF8toUTF16(string)); break; } case TYPE_int16_t: @@ -3924,8 +3938,7 @@ CData::ToSource(JSContext* cx, uintN argc, jsval *vp) source.Append(BuildDataSource(cx, typeObj, data, false)); source.Append(')'); - JSString* result = JS_NewUCStringCopyN(cx, - reinterpret_cast(source.get()), source.Length()); + JSString* result = NewUCString(cx, source); if (!result) return JS_FALSE; @@ -3982,7 +3995,7 @@ Int64Base::GetInt(JSContext* cx, JSObject* obj) { JS_ASSERT(Int64::IsInt64(cx, obj) || UInt64::IsUInt64(cx, obj)); jsval slot; - JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot)); return *static_cast(JSVAL_TO_PRIVATE(slot)); } @@ -4016,8 +4029,7 @@ Int64Base::ToString(JSContext* cx, intString = IntegerToString(static_cast(GetInt(cx, obj)), radix); } - JSString *result = JS_NewUCStringCopyN(cx, - reinterpret_cast(intString.get()), intString.Length()); + JSString *result = NewUCString(cx, intString); if (!result) return JS_FALSE; @@ -4048,8 +4060,7 @@ Int64Base::ToSource(JSContext* cx, } source.Append(NS_LITERAL_STRING("\")")); - JSString *result = JS_NewUCStringCopyN(cx, - reinterpret_cast(source.get()), source.Length()); + JSString *result = NewUCString(cx, source); if (!result) return JS_FALSE; @@ -4076,7 +4087,8 @@ Int64::Construct(JSContext* cx, // Get ctypes.Int64.prototype from the 'prototype' property of the ctor. jsval slot; - JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), "prototype", &slot); + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), + "prototype", &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); @@ -4217,7 +4229,7 @@ Int64::Join(JSContext* cx, uintN argc, jsval* vp) JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); jsval slot; - JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); @@ -4248,7 +4260,8 @@ UInt64::Construct(JSContext* cx, // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor. jsval slot; - JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), "prototype", &slot); + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), + "prototype", &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); @@ -4385,7 +4398,7 @@ UInt64::Join(JSContext* cx, uintN argc, jsval* vp) JSObject* callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)); jsval slot; - JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot); + ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); JSObject* proto = JSVAL_TO_OBJECT(slot); JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); diff --git a/js/ctypes/CTypes.h b/js/ctypes/CTypes.h index ada0acdf8839..d10863a2f010 100644 --- a/js/ctypes/CTypes.h +++ b/js/ctypes/CTypes.h @@ -175,10 +175,10 @@ public: static size_t GetAlignment(JSContext* cx, JSObject* obj); static ffi_type* GetFFIType(JSContext* cx, JSObject* obj); static JSString* GetName(JSContext* cx, JSObject* obj); - static JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); + static JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj); static JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); - static JSBool ProtoGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); + static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); static JSBool NameGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); @@ -196,7 +196,7 @@ public: static JSObject* GetBaseType(JSContext* cx, JSObject* obj); - static JSBool TargetGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); + static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); }; diff --git a/js/ctypes/Library.cpp b/js/ctypes/Library.cpp index 8660829be5c9..dd6e0a4deacc 100644 --- a/js/ctypes/Library.cpp +++ b/js/ctypes/Library.cpp @@ -129,7 +129,7 @@ Library::Create(JSContext* cx, jsval aPath) nsISupports* file = xpc->GetNativeOfWrapper(cx, JSVAL_TO_OBJECT(aPath)); nsCOMPtr localFile = do_QueryInterface(file); if (!localFile) { - JS_ReportError(cx, "open takes a string or nsIFile argument"); + JS_ReportError(cx, "open takes a string or nsILocalFile argument"); return NULL; } diff --git a/js/ctypes/tests/unit/test_jsctypes.js.in b/js/ctypes/tests/unit/test_jsctypes.js.in index b8a1d34ada8a..d2b04e448d7e 100644 --- a/js/ctypes/tests/unit/test_jsctypes.js.in +++ b/js/ctypes/tests/unit/test_jsctypes.js.in @@ -1111,7 +1111,7 @@ function run_jschar_tests(library, t, name, limits) { do_check_true(d.address().constructor === t.ptr); do_check_eq(d.address().contents, "a"); - do_check_eq(d.toSource(), "ctypes." + name + "(" + toprimitive(d.value) + ")"); + do_check_eq(d.toSource(), "ctypes." + name + "(\"" + d.value + "\")"); do_check_eq(d.toSource(), d.toString()); // Test string autoconversion (and lack thereof).