Bug 560002 - Opaque struct and definition support in ctypes. Part 2: Remove opaque pointers. r=benjamn

This commit is contained in:
Dan Witte 2010-05-03 16:20:43 -07:00
Родитель 35a3f39688
Коммит 905b76b87e
4 изменённых файлов: 58 добавлений и 120 удалений

Просмотреть файл

@ -905,7 +905,7 @@ InitTypeClasses(JSContext* cx, JSObject* parent)
if (!typeObj)
return false;
typeObj = PointerType::CreateInternal(cx, NULL, typeObj, NULL);
typeObj = PointerType::CreateInternal(cx, typeObj);
if (!typeObj)
return false;
if (!JS_DefineProperty(cx, parent, "voidptr_t", OBJECT_TO_JSVAL(typeObj),
@ -1703,20 +1703,18 @@ ImplicitConvert(JSContext* cx,
}
#include "typedefs.h"
case TYPE_pointer: {
JSObject* baseType = PointerType::GetBaseType(cx, targetType);
if (JSVAL_IS_NULL(val)) {
// Convert to a null pointer.
*static_cast<void**>(buffer) = NULL;
break;
}
JSObject* baseType = PointerType::GetBaseType(cx, targetType);
if (sourceData) {
// First, determine if the targetType is ctypes.void_t.ptr.
TypeCode sourceCode = CType::GetTypeCode(cx, sourceType);
void* sourceBuffer = CData::GetData(cx, sourceData);
bool voidptrTarget = baseType &&
CType::GetTypeCode(cx, baseType) == TYPE_void_t;
bool voidptrTarget = CType::GetTypeCode(cx, baseType) == TYPE_void_t;
if (sourceCode == TYPE_pointer && voidptrTarget) {
// Autoconvert if targetType is ctypes.voidptr_t.
@ -1733,7 +1731,7 @@ ImplicitConvert(JSContext* cx,
}
}
} else if (isArgument && baseType && JSVAL_IS_STRING(val)) {
} else if (isArgument && JSVAL_IS_STRING(val)) {
// Convert the string for the ffi call. This requires allocating space
// which the caller assumes ownership of.
// TODO: Extend this so we can safely convert strings at other times also.
@ -2037,23 +2035,15 @@ BuildTypeName(JSContext* cx, JSObject* typeObj)
// pointers on the left and arrays on the right. An excellent description
// of the rules for building C type declarations can be found at:
// http://unixwiz.net/techtips/reading-cdecl.html
JSObject* currentType = typeObj;
JSObject* nextType;
TypeCode prevGrouping = CType::GetTypeCode(cx, currentType), currentGrouping;
TypeCode prevGrouping = CType::GetTypeCode(cx, typeObj), currentGrouping;
while (1) {
currentGrouping = CType::GetTypeCode(cx, currentType);
currentGrouping = CType::GetTypeCode(cx, typeObj);
switch (currentGrouping) {
case TYPE_pointer: {
nextType = PointerType::GetBaseType(cx, currentType);
if (!nextType) {
// Opaque pointer type. Use the type's name as the base type.
break;
}
// Pointer types go on the left.
PrependString(result, "*");
currentType = nextType;
typeObj = PointerType::GetBaseType(cx, typeObj);
prevGrouping = currentGrouping;
continue;
}
@ -2067,17 +2057,17 @@ BuildTypeName(JSContext* cx, JSObject* typeObj)
// Array types go on the right.
AppendString(result, "[");
size_t length;
if (ArrayType::GetSafeLength(cx, currentType, &length))
if (ArrayType::GetSafeLength(cx, typeObj, &length))
IntegerToString(length, 10, result);
AppendString(result, "]");
currentType = ArrayType::GetBaseType(cx, currentType);
typeObj = ArrayType::GetBaseType(cx, typeObj);
prevGrouping = currentGrouping;
continue;
}
case TYPE_function: {
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, currentType);
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj);
// Add in the calling convention, if it's not cdecl.
if (GetABICode(cx, fninfo->mABI) == ABI_STDCALL)
@ -2100,10 +2090,10 @@ BuildTypeName(JSContext* cx, JSObject* typeObj)
AppendString(result, "...");
AppendString(result, ")");
// Set 'currentType' to the return type, and let the loop process it.
// Set 'typeObj' to the return type, and let the loop process it.
// 'prevGrouping' doesn't matter here, because functions cannot return
// arrays -- thus the parenthetical rules don't get tickled.
currentType = fninfo->mReturnType;
typeObj = fninfo->mReturnType;
continue;
}
default:
@ -2114,7 +2104,7 @@ BuildTypeName(JSContext* cx, JSObject* typeObj)
}
// Stick the base type and derived type parts together.
JSString* baseName = CType::GetName(cx, currentType);
JSString* baseName = CType::GetName(cx, typeObj);
PrependString(result, baseName);
return NewUCString(cx, result);
}
@ -2146,14 +2136,6 @@ BuildTypeSource(JSContext* cx,
}
case TYPE_pointer: {
JSObject* baseType = PointerType::GetBaseType(cx, typeObj);
if (!baseType) {
// Opaque pointer type. Use the type's name.
AppendString(result, "ctypes.PointerType(\"");
JSString* baseName = CType::GetName(cx, typeObj);
AppendString(result, baseName);
AppendString(result, "\")");
break;
}
// Specialcase ctypes.voidptr_t.
if (CType::GetTypeCode(cx, baseType) == TYPE_void_t) {
@ -2729,18 +2711,9 @@ CType::TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2)
// Determine whether the types require shallow or deep comparison.
switch (c1) {
case TYPE_pointer: {
// Compare base types.
JSObject* b1 = PointerType::GetBaseType(cx, t1);
JSObject* b2 = PointerType::GetBaseType(cx, t2);
if (!b1 || !b2) {
// One or both pointers are opaque.
// If both are opaque, compare names.
JSString* n1 = GetName(cx, t1);
JSString* n2 = GetName(cx, t2);
return b1 == b2 && JS_CompareStrings(n1, n2) == 0;
}
// Compare base types.
return TypesEqual(cx, b1, b2);
}
case TYPE_function: {
@ -2957,7 +2930,7 @@ CType::PtrGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
return JS_FALSE;
}
JSObject* pointerType = PointerType::CreateInternal(cx, NULL, obj, NULL);
JSObject* pointerType = PointerType::CreateInternal(cx, obj);
if (!pointerType)
return JS_FALSE;
@ -3081,23 +3054,12 @@ PointerType::Create(JSContext* cx, uintN argc, jsval* vp)
}
jsval arg = JS_ARGV(cx, vp)[0];
JSObject* baseType = NULL;
JSString* name = NULL;
if (!JSVAL_IS_PRIMITIVE(arg) &&
CType::IsCType(cx, JSVAL_TO_OBJECT(arg))) {
baseType = JSVAL_TO_OBJECT(arg);
} else if (JSVAL_IS_STRING(arg)) {
// Construct an opaque pointer type from a string.
name = JSVAL_TO_STRING(arg);
} else {
JS_ReportError(cx, "first argument must be a CType or a string");
if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(cx, JSVAL_TO_OBJECT(arg))) {
JS_ReportError(cx, "first argument must be a CType");
return JS_FALSE;
}
JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
JSObject* result = CreateInternal(cx, callee, baseType, name);
JSObject* result = CreateInternal(cx, JSVAL_TO_OBJECT(arg));
if (!result)
return JS_FALSE;
@ -3106,37 +3068,24 @@ PointerType::Create(JSContext* cx, uintN argc, jsval* vp)
}
JSObject*
PointerType::CreateInternal(JSContext* cx,
JSObject* ctor,
JSObject* baseType,
JSString* name)
PointerType::CreateInternal(JSContext* cx, JSObject* baseType)
{
JS_ASSERT(ctor || baseType);
JS_ASSERT((baseType && !name) || (!baseType && name));
if (baseType) {
// check if we have a cached PointerType on our base CType.
jsval slot;
ASSERT_OK(JS_GetReservedSlot(cx, baseType, SLOT_PTR, &slot));
if (!JSVAL_IS_VOID(slot))
return JSVAL_TO_OBJECT(slot);
}
// check if we have a cached PointerType on our base CType.
jsval slot;
ASSERT_OK(JS_GetReservedSlot(cx, baseType, SLOT_PTR, &slot));
if (!JSVAL_IS_VOID(slot))
return JSVAL_TO_OBJECT(slot);
// Get ctypes.PointerType.prototype and the common prototype for CData objects
// of this type, either from ctor or the baseType, whichever was provided.
// of this type.
JSObject* typeProto;
JSObject* dataProto;
if (ctor) {
typeProto = CType::GetProtoFromCtor(cx, ctor, SLOT_POINTERPROTO);
dataProto = CType::GetProtoFromCtor(cx, ctor, SLOT_POINTERDATAPROTO);
} else {
typeProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO);
dataProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERDATAPROTO);
}
typeProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO);
dataProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERDATAPROTO);
// Create a new CType object with the common properties and slots.
JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer,
name, INT_TO_JSVAL(sizeof(void*)),
NULL, INT_TO_JSVAL(sizeof(void*)),
INT_TO_JSVAL(ffi_type_pointer.alignment),
&ffi_type_pointer);
if (!typeObj)
@ -3147,17 +3096,15 @@ PointerType::CreateInternal(JSContext* cx,
if (!JS_SetReservedSlot(cx, typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType)))
return NULL;
if (baseType) {
// Determine the name of the PointerType, since it wasn't supplied.
JSString* nameStr = BuildTypeName(cx, typeObj);
if (!nameStr ||
!JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(nameStr)))
return NULL;
// Determine the name of the PointerType.
JSString* nameStr = BuildTypeName(cx, typeObj);
if (!nameStr ||
!JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(nameStr)))
return NULL;
// Finally, cache our newly-created PointerType on our pointed-to CType.
if (!JS_SetReservedSlot(cx, baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj)))
return NULL;
}
// Finally, cache our newly-created PointerType on our pointed-to CType.
if (!JS_SetReservedSlot(cx, baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj)))
return NULL;
return typeObj;
}
@ -3192,7 +3139,7 @@ PointerType::ConstructData(JSContext* cx,
if (argc >= 1) {
JSObject* baseObj = PointerType::GetBaseType(cx, obj);
if (baseObj && CType::GetTypeCode(cx, baseObj) == TYPE_function &&
if (CType::GetTypeCode(cx, baseObj) == TYPE_function &&
JSVAL_IS_OBJECT(argv[0]) &&
JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[0]))) {
// Construct a FunctionType.ptr from a JS function, and allow an
@ -3227,6 +3174,7 @@ PointerType::GetBaseType(JSContext* cx, JSObject* obj)
jsval type;
ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, &type));
JS_ASSERT(!JSVAL_IS_NULL(type));
return JSVAL_TO_OBJECT(type);
}
@ -3289,11 +3237,6 @@ PointerType::ContentsGetter(JSContext* cx,
}
JSObject* baseType = GetBaseType(cx, typeObj);
if (!baseType) {
JS_ReportError(cx, "cannot get contents of an opaque pointer type");
return JS_FALSE;
}
if (!CType::IsSizeDefined(cx, baseType)) {
JS_ReportError(cx, "cannot get contents of undefined size");
return JS_FALSE;
@ -3332,13 +3275,8 @@ PointerType::ContentsSetter(JSContext* cx,
}
JSObject* baseType = GetBaseType(cx, typeObj);
if (!baseType) {
JS_ReportError(cx, "cannot set contents of an opaque pointer type");
return JS_FALSE;
}
if (!CType::IsSizeDefined(cx, baseType)) {
JS_ReportError(cx, "cannot get contents of undefined size");
JS_ReportError(cx, "cannot set contents of undefined size");
return JS_FALSE;
}
@ -3586,6 +3524,7 @@ ArrayType::GetBaseType(JSContext* cx, JSObject* obj)
jsval type;
ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, &type));
JS_ASSERT(!JSVAL_IS_NULL(type));
return JSVAL_TO_OBJECT(type);
}
@ -3756,7 +3695,7 @@ ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval *vp)
}
JSObject* baseType = GetBaseType(cx, typeObj);
JSObject* pointerType = PointerType::CreateInternal(cx, NULL, baseType, NULL);
JSObject* pointerType = PointerType::CreateInternal(cx, baseType);
if (!pointerType)
return JS_FALSE;
js::AutoValueRooter root(cx, pointerType);
@ -4332,7 +4271,7 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval *vp)
return JS_FALSE;
JSObject* baseType = field->mType;
JSObject* pointerType = PointerType::CreateInternal(cx, NULL, baseType, NULL);
JSObject* pointerType = PointerType::CreateInternal(cx, baseType);
if (!pointerType)
return JS_FALSE;
js::AutoValueRooter root(cx, pointerType);
@ -4418,7 +4357,7 @@ PrepareType(JSContext* cx, jsval type)
// convert array argument types to pointers, just like C.
// ImplicitConvert will do the same, when passing an array as data.
JSObject* baseType = ArrayType::GetBaseType(cx, result);
result = PointerType::CreateInternal(cx, NULL, baseType, NULL);
result = PointerType::CreateInternal(cx, baseType);
if (!result)
return NULL;
@ -4762,9 +4701,13 @@ FunctionType::Call(JSContext* cx,
}
JSObject* typeObj = CData::GetCType(cx, obj);
if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer ||
!(typeObj = PointerType::GetBaseType(cx, typeObj)) ||
CType::GetTypeCode(cx, typeObj) != TYPE_function) {
if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) {
JS_ReportError(cx, "not a FunctionType.ptr");
return false;
}
typeObj = PointerType::GetBaseType(cx, typeObj);
if (CType::GetTypeCode(cx, typeObj) != TYPE_function) {
JS_ReportError(cx, "not a FunctionType.ptr");
return false;
}
@ -5347,7 +5290,7 @@ CData::Address(JSContext* cx, uintN argc, jsval *vp)
}
JSObject* typeObj = CData::GetCType(cx, obj);
JSObject* pointerType = PointerType::CreateInternal(cx, NULL, typeObj, NULL);
JSObject* pointerType = PointerType::CreateInternal(cx, typeObj);
if (!pointerType)
return JS_FALSE;
js::AutoValueRooter root(cx, pointerType);
@ -5434,11 +5377,6 @@ CData::ReadString(JSContext* cx, uintN argc, jsval *vp)
switch (typeCode) {
case TYPE_pointer:
baseType = PointerType::GetBaseType(cx, typeObj);
if (!baseType) {
JS_ReportError(cx, "cannot read contents of pointer to opaque type");
return JS_FALSE;
}
data = *static_cast<void**>(GetData(cx, obj));
if (data == NULL) {
JS_ReportError(cx, "cannot read contents of null pointer");

Просмотреть файл

@ -405,8 +405,7 @@ namespace CType {
}
namespace PointerType {
JSObject* CreateInternal(JSContext* cx, JSObject* ctor, JSObject* baseType,
JSString* name);
JSObject* CreateInternal(JSContext* cx, JSObject* baseType);
JSObject* GetBaseType(JSContext* cx, JSObject* obj);
}

Просмотреть файл

@ -253,7 +253,7 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp)
root.setObject(typeObj);
// Make a function pointer type.
typeObj = PointerType::CreateInternal(cx, NULL, typeObj, NULL);
typeObj = PointerType::CreateInternal(cx, typeObj);
if (!typeObj)
return JS_FALSE;
root.setObject(typeObj);

Просмотреть файл

@ -1633,13 +1633,14 @@ function ptrValue(p) {
function run_PointerType_tests() {
run_type_ctor_class_tests(ctypes.PointerType,
ctypes.PointerType(ctypes.int32_t), ctypes.PointerType("FILE"),
ctypes.PointerType(ctypes.int32_t), ctypes.PointerType(ctypes.int64_t),
[ "targetType" ], [], [ "contents" ], [ "isNull" ], []);
do_check_throws(function() { ctypes.PointerType(); }, Error);
do_check_throws(function() { ctypes.PointerType(ctypes.int32_t, 5); }, Error);
do_check_throws(function() { ctypes.PointerType(null); }, Error);
do_check_throws(function() { ctypes.PointerType(ctypes.int32_t()); }, Error);
do_check_throws(function() { ctypes.PointerType("void"); }, Error);
let name = "g_t";
let g_t = ctypes.StructType(name, [{ a: ctypes.int32_t }, { b: ctypes.double }]);
@ -1675,15 +1676,15 @@ function run_PointerType_tests() {
do_check_throws(function() { p.value = 5; }, Error);
// Test opaque pointers.
let f_t = ctypes.PointerType("FILE*");
let f_t = ctypes.StructType("FILE").ptr;
do_check_eq(f_t.name, "FILE*");
do_check_eq(f_t.toSource(), "ctypes.PointerType(\"FILE*\")");
do_check_eq(f_t.toSource(), 'ctypes.StructType("FILE").ptr');
let f = new f_t();
do_check_throws(function() { f.contents; }, Error);
do_check_throws(function() { f.contents = 0; }, Error);
let f = f_t(5);
do_check_throws(function() { f.contents = 0; }, Error);
do_check_eq(f.toSource(), "ctypes.PointerType(\"FILE*\")(ctypes.UInt64(\"0x5\"))");
do_check_eq(f.toSource(), 'FILE.ptr(ctypes.UInt64("0x5"))');
do_check_throws(function() { f_t(p); }, Error);
do_check_throws(function() { f.value = p; }, Error);