зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 15 changesets (bug 1475409, bug 1461450, bug 1474369
, bug 1471726) for causing rooting hazards and browser chrome failures. CLOSED TREE
Backed out changeset 7ce27aa3ce68 (bug1474369
) Backed out changeset a8a4e2414daa (bug1474369
) Backed out changeset 13c9626970e2 (bug1474369
) Backed out changeset 9817819b7765 (bug 1475409) Backed out changeset 39fcebfe6529 (bug 1475409) Backed out changeset c19ca740d3d1 (bug 1475409) Backed out changeset b26c90518fca (bug1474369
) Backed out changeset cbdde0474521 (bug1474369
) Backed out changeset ccea3049fe0f (bug1474369
) Backed out changeset e9f6d2544a82 (bug1474369
) Backed out changeset 99c4d07d4b88 (bug1474369
) Backed out changeset c721ada8a6d6 (bug 1461450) Backed out changeset 961379be0f5e (bug 1461450) Backed out changeset cf2448b2635f (bug 1471726) Backed out changeset 408961783c95 (bug 1471726)
This commit is contained in:
Родитель
a78b7458a9
Коммит
e748fd8968
|
@ -197,7 +197,7 @@ def interfaces(iface):
|
|||
interfaces = []
|
||||
while iface.base:
|
||||
interfaces.append(iface)
|
||||
iface = iface.idl.getName(xpidl.TypeId(iface.base), iface.location)
|
||||
iface = iface.idl.getName(iface.base, iface.location)
|
||||
interfaces.append(iface)
|
||||
interfaces.reverse()
|
||||
return interfaces
|
||||
|
|
|
@ -58,7 +58,7 @@ XPCConvert::IsMethodReflectable(const nsXPTMethodInfo& info)
|
|||
|
||||
// Reflected methods can't use native types. All native types end up
|
||||
// getting tagged as void*, so this check is easy.
|
||||
if (type.Tag() == nsXPTType::T_VOID)
|
||||
if (type.TagPart() == nsXPTType::T_VOID)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -108,7 +108,7 @@ XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
||||
switch (type.Tag()) {
|
||||
switch (type.TagPart()) {
|
||||
case nsXPTType::T_I8 :
|
||||
d.setInt32(*static_cast<const int8_t*>(s));
|
||||
return true;
|
||||
|
@ -385,16 +385,9 @@ XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
return true;
|
||||
}
|
||||
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
return NativeArray2JS(d, *static_cast<const void* const*>(s),
|
||||
type.ArrayElementType(), iid, arrlen, pErr);
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
auto* array = static_cast<const xpt::detail::UntypedTArray*>(s);
|
||||
return NativeArray2JS(d, array->Elements(), type.ArrayElementType(),
|
||||
iid, array->Length(), pErr);
|
||||
}
|
||||
return NativeArray2JS(d, static_cast<const void* const*>(s),
|
||||
type.ArrayElementType(), iid, arrlen, pErr);
|
||||
|
||||
default:
|
||||
NS_ERROR("bad type");
|
||||
|
@ -455,7 +448,7 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
|||
bool sizeis = type.Tag() == TD_PSTRING_SIZE_IS ||
|
||||
type.Tag() == TD_PWSTRING_SIZE_IS;
|
||||
|
||||
switch (type.Tag()) {
|
||||
switch (type.TagPart()) {
|
||||
case nsXPTType::T_I8 :
|
||||
return ConvertToPrimitive(cx, s, static_cast<int8_t*>(d));
|
||||
case nsXPTType::T_I16 :
|
||||
|
@ -841,70 +834,9 @@ XPCConvert::JSData2Native(void* d, HandleValue s,
|
|||
return ok;
|
||||
}
|
||||
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
{
|
||||
void** dest = (void**)d;
|
||||
const nsXPTType& elty = type.ArrayElementType();
|
||||
|
||||
*dest = nullptr;
|
||||
|
||||
// FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
|
||||
// its caller if arrlen is 0, allowing arbitrary values to be passed as
|
||||
// arrays and interpreted as the empty array (bug 1458987).
|
||||
//
|
||||
// NOTE: Once this is fixed, null/undefined should be allowed for arrays if
|
||||
// arrlen is 0.
|
||||
if (arrlen == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
|
||||
// Check that we have enough elements in our array.
|
||||
if (*aLength < arrlen) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return nullptr;
|
||||
}
|
||||
*aLength = arrlen;
|
||||
|
||||
// Allocate the backing buffer & return it.
|
||||
*dest = moz_xmalloc(*aLength * elty.Stride());
|
||||
if (!*dest) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return nullptr;
|
||||
}
|
||||
return *dest;
|
||||
});
|
||||
|
||||
if (!ok && *dest) {
|
||||
// An error occurred, free any allocated backing buffer.
|
||||
free(*dest);
|
||||
*dest = nullptr;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
auto* dest = (xpt::detail::UntypedTArray*)d;
|
||||
const nsXPTType& elty = type.ArrayElementType();
|
||||
|
||||
bool ok = JSArray2Native(s, elty, iid, pErr, [&] (uint32_t* aLength) -> void* {
|
||||
if (!dest->SetLength(elty, *aLength)) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return nullptr;
|
||||
}
|
||||
return dest->Elements();
|
||||
});
|
||||
|
||||
if (!ok) {
|
||||
// An error occurred, free any allocated backing buffer.
|
||||
dest->Clear();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
return JSArray2Native((void**)d, s, arrlen,
|
||||
type.ArrayElementType(), iid, pErr);
|
||||
|
||||
default:
|
||||
NS_ERROR("bad type");
|
||||
|
@ -1400,16 +1332,39 @@ XPCConvert::JSValToXPCException(MutableHandleValue s,
|
|||
|
||||
// array fun...
|
||||
|
||||
static bool
|
||||
ValidArrayType(const nsXPTType& type)
|
||||
{
|
||||
switch (type.Tag()) {
|
||||
// These types aren't allowed to be in arrays.
|
||||
case nsXPTType::T_VOID:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_PSTRING_SIZE_IS:
|
||||
case nsXPTType::T_PWSTRING_SIZE_IS:
|
||||
case nsXPTType::T_ARRAY:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::NativeArray2JS(MutableHandleValue d, const void* buf,
|
||||
XPCConvert::NativeArray2JS(MutableHandleValue d, const void* const* s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr)
|
||||
{
|
||||
MOZ_ASSERT(buf || count == 0, "Must have buf or 0 elements");
|
||||
MOZ_ASSERT(s, "bad param");
|
||||
|
||||
AutoJSContext cx;
|
||||
|
||||
// XXX add support for putting chars in a string rather than an array
|
||||
|
||||
// XXX add support to indicate *which* array element was not convertable
|
||||
|
||||
RootedObject array(cx, JS_NewArrayObject(cx, count));
|
||||
if (!array)
|
||||
return false;
|
||||
|
@ -1417,9 +1372,12 @@ XPCConvert::NativeArray2JS(MutableHandleValue d, const void* buf,
|
|||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
|
||||
|
||||
if (!ValidArrayType(type))
|
||||
return false;
|
||||
|
||||
RootedValue current(cx, JS::NullValue());
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (!NativeData2JS(¤t, type.ElementPtr(buf, i), type, iid, 0, pErr) ||
|
||||
if (!NativeData2JS(¤t, type.ElementPtr(*s, i), type, iid, 0, pErr) ||
|
||||
!JS_DefineElement(cx, array, i, current, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
|
@ -1430,123 +1388,223 @@ XPCConvert::NativeArray2JS(MutableHandleValue d, const void* buf,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Fast conversion of typed arrays to native using memcpy.
|
||||
// No float or double canonicalization is done. Called by
|
||||
// JSarray2Native whenever a TypedArray is met. ArrayBuffers
|
||||
// are not accepted; create a properly typed array view on them
|
||||
// first. The element type of array must match the XPCOM
|
||||
// type in size, type and signedness exactly. As an exception,
|
||||
// Uint8ClampedArray is allowed for arrays of uint8_t. DataViews
|
||||
// are not supported.
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::JSArray2Native(JS::HandleValue aJSVal,
|
||||
const nsXPTType& aEltType,
|
||||
const nsIID* aIID,
|
||||
nsresult* pErr,
|
||||
const ArrayAllocFixupLen& aAllocFixupLen)
|
||||
XPCConvert::JSTypedArray2Native(void** d,
|
||||
JSObject* jsArray,
|
||||
uint32_t count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr)
|
||||
{
|
||||
// Wrap aAllocFixupLen to check length is within bounds & initialize the
|
||||
// allocated memory if needed.
|
||||
auto allocFixupLen = [&] (uint32_t* aLength) -> void* {
|
||||
if (*aLength > (UINT32_MAX / aEltType.Stride())) {
|
||||
return nullptr; // Byte length doesn't fit in uint32_t
|
||||
}
|
||||
MOZ_ASSERT(jsArray, "bad param");
|
||||
MOZ_ASSERT(d, "bad param");
|
||||
MOZ_ASSERT(JS_IsTypedArrayObject(jsArray), "not a typed array");
|
||||
|
||||
void* buf = aAllocFixupLen(aLength);
|
||||
// Check the actual length of the input array against the
|
||||
// given size_is.
|
||||
uint32_t len = JS_GetTypedArrayLength(jsArray);
|
||||
if (len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
|
||||
// Ensure the buffer has valid values for each element. We can skip this
|
||||
// for arithmetic types, as they do not require initialization.
|
||||
if (buf && !aEltType.IsArithmetic()) {
|
||||
for (uint32_t i = 0; i < *aLength; ++i) {
|
||||
InitializeValue(aEltType, aEltType.ElementPtr(buf, i));
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t expected;
|
||||
switch (JS_GetArrayBufferViewType(jsArray)) {
|
||||
case js::Scalar::Int8:
|
||||
expected = nsXPTType::T_I8;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint8:
|
||||
case js::Scalar::Uint8Clamped:
|
||||
expected = nsXPTType::T_U8;
|
||||
break;
|
||||
|
||||
case js::Scalar::Int16:
|
||||
expected = nsXPTType::T_I16;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint16:
|
||||
expected = nsXPTType::T_U16;
|
||||
break;
|
||||
|
||||
case js::Scalar::Int32:
|
||||
expected = nsXPTType::T_I32;
|
||||
break;
|
||||
|
||||
case js::Scalar::Uint32:
|
||||
expected = nsXPTType::T_U32;
|
||||
break;
|
||||
|
||||
case js::Scalar::Float32:
|
||||
expected = nsXPTType::T_FLOAT;
|
||||
break;
|
||||
|
||||
case js::Scalar::Float64:
|
||||
expected = nsXPTType::T_DOUBLE;
|
||||
break;
|
||||
|
||||
// Yet another array type was defined? It is not supported yet...
|
||||
default:
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the type we got is the type we expected.
|
||||
if (expected != type.Tag()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the size would overflow uint32_t.
|
||||
if (count > (UINT32_MAX / type.Stride())) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the backing memory buffer to copy out of.
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared;
|
||||
void* buf = JS_GetArrayBufferViewData(jsArray, &isShared, nogc);
|
||||
|
||||
// Require opting in to shared memory - a future project.
|
||||
if (isShared) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the buffer, and copy.
|
||||
*d = moz_xmalloc(count * type.Stride());
|
||||
if (!*d) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*d, buf, count * type.Stride());
|
||||
|
||||
if (pErr)
|
||||
*pErr = NS_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
XPCConvert::JSArray2Native(void** d, HandleValue s,
|
||||
uint32_t count, const nsXPTType& type,
|
||||
const nsID* iid, nsresult* pErr)
|
||||
{
|
||||
MOZ_ASSERT(d, "bad param");
|
||||
|
||||
AutoJSContext cx;
|
||||
|
||||
// JSArray2Native only accepts objects (Array and TypedArray).
|
||||
if (!aJSVal.isObject()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
|
||||
return false;
|
||||
// FIXME: XPConnect historically has shortcut the JSArray2Native codepath in
|
||||
// its caller if count is 0, allowing arbitrary values to be passed as
|
||||
// arrays and interpreted as the empty array (bug 1458987).
|
||||
//
|
||||
// NOTE: Once this is fixed, null/undefined should be allowed for arrays if
|
||||
// count is 0.
|
||||
if (count == 0) {
|
||||
*d = nullptr;
|
||||
return true;
|
||||
}
|
||||
RootedObject jsarray(cx, &aJSVal.toObject());
|
||||
|
||||
// XXX add support for getting chars from strings
|
||||
|
||||
// XXX add support to indicate *which* array element was not convertable
|
||||
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
if (JS_IsTypedArrayObject(jsarray)) {
|
||||
// Fast conversion of typed arrays to native using memcpy. No float or
|
||||
// double canonicalization is done. ArrayBuffers are not accepted;
|
||||
// create a properly typed array view on them first. The element type of
|
||||
// array must match the XPCOM type in size, type and signedness exactly.
|
||||
// As an exception, Uint8ClampedArray is allowed for arrays of uint8_t.
|
||||
// DataViews are not supported.
|
||||
if (!ValidArrayType(type))
|
||||
return false;
|
||||
|
||||
nsXPTTypeTag tag;
|
||||
switch (JS_GetArrayBufferViewType(jsarray)) {
|
||||
case js::Scalar::Int8: tag = TD_INT8; break;
|
||||
case js::Scalar::Uint8: tag = TD_UINT8; break;
|
||||
case js::Scalar::Uint8Clamped: tag = TD_UINT8; break;
|
||||
case js::Scalar::Int16: tag = TD_INT16; break;
|
||||
case js::Scalar::Uint16: tag = TD_UINT16; break;
|
||||
case js::Scalar::Int32: tag = TD_INT32; break;
|
||||
case js::Scalar::Uint32: tag = TD_UINT32; break;
|
||||
case js::Scalar::Float32: tag = TD_FLOAT; break;
|
||||
case js::Scalar::Float64: tag = TD_DOUBLE; break;
|
||||
default: return false;
|
||||
}
|
||||
if (aEltType.Tag() != tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the backing memory buffer to copy out of.
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared = false;
|
||||
const void* data = JS_GetArrayBufferViewData(jsarray, &isShared, nogc);
|
||||
|
||||
// Require opting in to shared memory - a future project.
|
||||
if (isShared) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t length = JS_GetTypedArrayLength(jsarray);
|
||||
void* buf = allocFixupLen(&length);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Directly copy data into the allocated target buffer.
|
||||
memcpy(buf, data, length * aEltType.Stride());
|
||||
return true;
|
||||
if (s.isNullOrUndefined()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If jsarray is not a TypedArrayObject, check for an Array object.
|
||||
uint32_t length = 0;
|
||||
bool isArray = false;
|
||||
if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray ||
|
||||
!JS_GetArrayLength(cx, jsarray, &length)) {
|
||||
if (!s.isObject()) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject jsarray(cx, &s.toObject());
|
||||
|
||||
// If this is a typed array, then try a fast conversion with memcpy.
|
||||
if (JS_IsTypedArrayObject(jsarray)) {
|
||||
return JSTypedArray2Native(d, jsarray, count, type, pErr);
|
||||
}
|
||||
|
||||
bool isArray;
|
||||
if (!JS_IsArrayObject(cx, jsarray, &isArray) || !isArray) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
void* buf = allocFixupLen(&length);
|
||||
if (!buf) {
|
||||
uint32_t len;
|
||||
if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Translate each array element separately.
|
||||
RootedValue current(cx);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
if (!JS_GetElement(cx, jsarray, i, ¤t) ||
|
||||
!JSData2Native(aEltType.ElementPtr(buf, i), current,
|
||||
aEltType, aIID, 0, pErr)) {
|
||||
// Array element conversion failed. Clean up all elements converted
|
||||
// before the error. Caller handles freeing 'buf'.
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
CleanupValue(aEltType, aEltType.ElementPtr(buf, j));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (count > (UINT32_MAX / type.Stride())) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Allocate the destination array, and begin converting elements.
|
||||
*d = moz_xmalloc(count * type.Stride());
|
||||
if (!*d) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue current(cx);
|
||||
uint32_t initedCount;
|
||||
for (initedCount = 0; initedCount < count; ++initedCount) {
|
||||
if (!JS_GetElement(cx, jsarray, initedCount, ¤t) ||
|
||||
!JSData2Native(type.ElementPtr(*d, initedCount),
|
||||
current, type, iid, 0, pErr))
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we handled every array element.
|
||||
if (initedCount == count) {
|
||||
if (pErr)
|
||||
*pErr = NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Something failed! Clean up after ourselves.
|
||||
for (uint32_t i = 0; i < initedCount; ++i) {
|
||||
CleanupValue(type, type.ElementPtr(*d, i));
|
||||
}
|
||||
free(*d);
|
||||
*d = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -1561,7 +1619,7 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
|||
MOZ_ASSERT(aArrayLen == 0 ||
|
||||
aType.Tag() == nsXPTType::T_PSTRING_SIZE_IS ||
|
||||
aType.Tag() == nsXPTType::T_PWSTRING_SIZE_IS ||
|
||||
aType.Tag() == nsXPTType::T_LEGACY_ARRAY,
|
||||
aType.Tag() == nsXPTType::T_ARRAY,
|
||||
"Array lengths may only appear for certain types!");
|
||||
|
||||
switch (aType.Tag()) {
|
||||
|
@ -1598,8 +1656,8 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
|||
free(*(void**)aValue);
|
||||
break;
|
||||
|
||||
// Legacy Array Type
|
||||
case nsXPTType::T_LEGACY_ARRAY:
|
||||
// Array Types
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
void* elements = *(void**)aValue;
|
||||
|
@ -1610,69 +1668,10 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
|||
free(elements);
|
||||
break;
|
||||
}
|
||||
|
||||
// Array Type
|
||||
case nsXPTType::T_ARRAY:
|
||||
{
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
auto* array = (xpt::detail::UntypedTArray*)aValue;
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); ++i) {
|
||||
CleanupValue(elty, elty.ElementPtr(array->Elements(), i));
|
||||
}
|
||||
array->Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the JS::Value to `undefined`
|
||||
case nsXPTType::T_JSVAL:
|
||||
((JS::Value*)aValue)->setUndefined();
|
||||
break;
|
||||
|
||||
// Non-arithmetic types requiring no cleanup
|
||||
case nsXPTType::T_VOID:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown Type!");
|
||||
}
|
||||
|
||||
// Clear any non-complex values to the valid '0' state.
|
||||
if (!aType.IsComplex()) {
|
||||
aType.ZeroValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// Implementation of xpc::InitializeValue.
|
||||
|
||||
void
|
||||
xpc::InitializeValue(const nsXPTType& aType, void* aValue)
|
||||
{
|
||||
switch (aType.Tag()) {
|
||||
// Types which require custom, specific initialization.
|
||||
case nsXPTType::T_JSVAL:
|
||||
new (aValue) JS::Value();
|
||||
MOZ_ASSERT(reinterpret_cast<JS::Value*>(aValue)->isUndefined());
|
||||
break;
|
||||
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
new (aValue) nsString();
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
new (aValue) nsCString();
|
||||
break;
|
||||
|
||||
case nsXPTType::T_ARRAY:
|
||||
new (aValue) xpt::detail::UntypedTArray();
|
||||
break;
|
||||
|
||||
// The remaining types all have valid states where all bytes are '0'.
|
||||
default:
|
||||
aType.ZeroValue(aValue);
|
||||
break;
|
||||
// Null out the pointer if we have it.
|
||||
if (aType.HasPointerRepr()) {
|
||||
*(void**)aValue = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -530,10 +530,7 @@ xpc::CleanupValue(const nsXPTType& aType,
|
|||
// Check if we can do a cheap early return, and only perform the inner call
|
||||
// if we can't. We never have to clean up null pointer types or arithmetic
|
||||
// types.
|
||||
//
|
||||
// NOTE: We can skip zeroing arithmetic types in CleanupValue, as they are
|
||||
// already in a valid state.
|
||||
if (aType.IsArithmetic() || (aType.IsPointer() && !*(void**)aValue)) {
|
||||
if (aType.IsArithmetic() || (aType.HasPointerRepr() && !*(void**)aValue)) {
|
||||
return;
|
||||
}
|
||||
xpc::InnerCleanupValue(aType, aValue, aArrayLen);
|
||||
|
|
|
@ -672,7 +672,7 @@ nsXPCWrappedJSClass::GetArraySizeFromParam(const nsXPTMethodInfo* method,
|
|||
nsXPTCMiniVariant* nativeParams,
|
||||
uint32_t* result) const
|
||||
{
|
||||
if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
|
||||
if (type.Tag() != nsXPTType::T_ARRAY &&
|
||||
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
|
||||
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
|
||||
*result = 0;
|
||||
|
@ -749,27 +749,25 @@ nsXPCWrappedJSClass::CleanupOutparams(const nsXPTMethodInfo* info,
|
|||
if (!param.IsOut())
|
||||
continue;
|
||||
|
||||
// Extract the array length so we can use it in CleanupValue.
|
||||
uint32_t arrayLen = 0;
|
||||
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
||||
continue;
|
||||
|
||||
MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
|
||||
|
||||
// Call 'CleanupValue' on parameters which we know to be initialized:
|
||||
// 1. Complex parameters (initialized by caller)
|
||||
// 2. 'inout' parameters (initialized by caller)
|
||||
// 3. 'out' parameters when 'inOutOnly' is 'false' (initialized by us)
|
||||
//
|
||||
// We skip non-complex 'out' parameters before the call, as they may
|
||||
// contain random junk.
|
||||
if (param.Type().IsComplex() || param.IsIn() || !inOutOnly) {
|
||||
uint32_t arrayLen = 0;
|
||||
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
||||
continue;
|
||||
|
||||
// The inOutOnly flag is necessary because full outparams may contain
|
||||
// uninitialized junk before the call is made, and we don't want to try
|
||||
// to clean up uninitialized junk.
|
||||
if (!inOutOnly || param.IsIn()) {
|
||||
xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
|
||||
}
|
||||
|
||||
// Ensure our parameters are in a clean state. Complex values are always
|
||||
// handled by CleanupValue, and others have a valid null representation.
|
||||
if (!param.Type().IsComplex()) {
|
||||
param.Type().ZeroValue(nativeParams[i].val.p);
|
||||
// Even if we didn't call CleanupValue, null out any pointers. This is
|
||||
// just to protect C++ callers which may read garbage if they forget to
|
||||
// check the error value.
|
||||
if (param.Type().HasPointerRepr()) {
|
||||
*(void**)nativeParams[i].val.p = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1245,6 +1245,10 @@ CallMethodHelper::Call()
|
|||
CallMethodHelper::~CallMethodHelper()
|
||||
{
|
||||
for (nsXPTCVariant& param : mDispatchParams) {
|
||||
// Only clean up values which need cleanup.
|
||||
if (!param.DoesValNeedCleanup())
|
||||
continue;
|
||||
|
||||
uint32_t arraylen = 0;
|
||||
if (!GetArraySizeFromParam(param.type, UndefinedHandleValue, &arraylen))
|
||||
continue;
|
||||
|
@ -1258,7 +1262,7 @@ CallMethodHelper::GetArraySizeFromParam(const nsXPTType& type,
|
|||
HandleValue maybeArray,
|
||||
uint32_t* result)
|
||||
{
|
||||
if (type.Tag() != nsXPTType::T_LEGACY_ARRAY &&
|
||||
if (type.Tag() != nsXPTType::T_ARRAY &&
|
||||
type.Tag() != nsXPTType::T_PSTRING_SIZE_IS &&
|
||||
type.Tag() != nsXPTType::T_PWSTRING_SIZE_IS) {
|
||||
*result = 0;
|
||||
|
@ -1473,39 +1477,25 @@ CallMethodHelper::InitializeDispatchParams()
|
|||
|
||||
mJSContextIndex = mMethodInfo->IndexOfJSContext();
|
||||
|
||||
// Allocate enough space in mDispatchParams up-front.
|
||||
if (!mDispatchParams.AppendElements(paramCount + wantsJSContext + wantsOptArgc)) {
|
||||
Throw(NS_ERROR_OUT_OF_MEMORY, mCallContext);
|
||||
return false;
|
||||
// iterate through the params to clear flags (for safe cleanup later)
|
||||
for (uint8_t i = 0; i < paramCount + wantsJSContext + wantsOptArgc; i++) {
|
||||
nsXPTCVariant* dp = mDispatchParams.AppendElement();
|
||||
dp->ClearFlags();
|
||||
dp->val.p = nullptr;
|
||||
}
|
||||
|
||||
// Initialize each parameter to a valid state (for safe cleanup later).
|
||||
for (uint8_t i = 0, paramIdx = 0; i < mDispatchParams.Length(); i++) {
|
||||
nsXPTCVariant& dp = mDispatchParams[i];
|
||||
// Fill in the JSContext argument
|
||||
if (wantsJSContext) {
|
||||
nsXPTCVariant* dp = &mDispatchParams[mJSContextIndex];
|
||||
dp->type = nsXPTType::T_VOID;
|
||||
dp->val.p = mCallContext;
|
||||
}
|
||||
|
||||
if (i == mJSContextIndex) {
|
||||
// Fill in the JSContext argument
|
||||
dp.type = nsXPTType::T_VOID;
|
||||
dp.val.p = mCallContext;
|
||||
} else if (i == mOptArgcIndex) {
|
||||
// Fill in the optional_argc argument
|
||||
dp.type = nsXPTType::T_U8;
|
||||
dp.val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
|
||||
} else {
|
||||
// Initialize normal arguments.
|
||||
const nsXPTParamInfo& param = mMethodInfo->Param(paramIdx);
|
||||
dp.type = param.Type();
|
||||
xpc::InitializeValue(dp.type, &dp.val);
|
||||
|
||||
// Specify the correct storage/calling semantics. This will also set
|
||||
// the `ptr` field to be self-referential.
|
||||
if (param.IsIndirect()) {
|
||||
dp.SetIndirect();
|
||||
}
|
||||
|
||||
// Advance to the next normal parameter.
|
||||
paramIdx++;
|
||||
}
|
||||
// Fill in the optional_argc argument
|
||||
if (wantsOptArgc) {
|
||||
nsXPTCVariant* dp = &mDispatchParams[mOptArgcIndex];
|
||||
dp->type = nsXPTType::T_U8;
|
||||
dp->val.u8 = std::min<uint32_t>(mArgc, paramCount) - requiredArgs;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1532,8 +1522,40 @@ bool
|
|||
CallMethodHelper::ConvertIndependentParam(uint8_t i)
|
||||
{
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
|
||||
const nsXPTType& type = paramInfo.Type();
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
nsXPTCVariant* dp = GetDispatchParam(i);
|
||||
dp->type = type;
|
||||
MOZ_ASSERT(!paramInfo.IsShared(), "[shared] implies [noscript]!");
|
||||
|
||||
// Specify the correct storage/calling semantics.
|
||||
if (paramInfo.IsIndirect())
|
||||
dp->SetIndirect();
|
||||
|
||||
// Some types are always stored within the nsXPTCVariant, and passed
|
||||
// indirectly, regardless of in/out-ness. These types are stored in the
|
||||
// nsXPTCVariant's extended value.
|
||||
switch (type.Tag()) {
|
||||
// Ensure that the jsval has a valid value.
|
||||
case nsXPTType::T_JSVAL:
|
||||
new (&dp->ext.jsval) JS::Value();
|
||||
MOZ_ASSERT(dp->ext.jsval.isUndefined());
|
||||
break;
|
||||
|
||||
// Initialize our temporary string class values so they can be assigned
|
||||
// to by the XPCConvert logic.
|
||||
case nsXPTType::T_ASTRING:
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
new (&dp->ext.nsstr) nsString();
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
new (&dp->ext.nscstr) nsCString();
|
||||
break;
|
||||
}
|
||||
|
||||
// Flag cleanup for anything that isn't self-contained.
|
||||
if (!type.IsArithmetic())
|
||||
dp->SetValNeedsCleanup();
|
||||
|
||||
// Even if there's nothing to convert, we still need to examine the
|
||||
// JSObject container for out-params. If it's null or otherwise invalid,
|
||||
|
@ -1619,8 +1641,18 @@ bool
|
|||
CallMethodHelper::ConvertDependentParam(uint8_t i)
|
||||
{
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(i);
|
||||
const nsXPTType& type = paramInfo.Type();
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
|
||||
nsXPTCVariant* dp = GetDispatchParam(i);
|
||||
dp->type = type;
|
||||
|
||||
// Specify the correct storage/calling semantics.
|
||||
if (paramInfo.IsIndirect())
|
||||
dp->SetIndirect();
|
||||
|
||||
// Make sure we clean up all of our dependent types. All of them require
|
||||
// allocations of some kind.
|
||||
dp->SetValNeedsCleanup();
|
||||
|
||||
// Even if there's nothing to convert, we still need to examine the
|
||||
// JSObject container for out-params. If it's null or otherwise invalid,
|
||||
|
@ -1680,18 +1712,14 @@ TraceParam(JSTracer* aTrc, void* aVal, const nsXPTType& aType,
|
|||
if (aType.Tag() == nsXPTType::T_JSVAL) {
|
||||
JS::UnsafeTraceRoot(aTrc, (JS::Value*)aVal,
|
||||
"XPCWrappedNative::CallMethod param");
|
||||
} else if (aType.Tag() == nsXPTType::T_ARRAY) {
|
||||
auto* array = (xpt::detail::UntypedTArray*)aVal;
|
||||
} else if (aType.Tag() == nsXPTType::T_ARRAY && *(void**)aVal) {
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); ++i) {
|
||||
TraceParam(aTrc, elty.ElementPtr(array->Elements(), i), elty);
|
||||
if (elty.Tag() != nsXPTType::T_JSVAL) {
|
||||
return;
|
||||
}
|
||||
} else if (aType.Tag() == nsXPTType::T_LEGACY_ARRAY && *(void**)aVal) {
|
||||
const nsXPTType& elty = aType.ArrayElementType();
|
||||
|
||||
for (uint32_t i = 0; i < aArrayLen; ++i) {
|
||||
TraceParam(aTrc, elty.ElementPtr(*(void**)aVal, i), elty);
|
||||
TraceParam(aTrc, elty.ElementPtr(aVal, i), elty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1701,8 +1729,9 @@ CallMethodHelper::trace(JSTracer* aTrc)
|
|||
{
|
||||
// We need to note each of our initialized parameters which contain jsvals.
|
||||
for (nsXPTCVariant& param : mDispatchParams) {
|
||||
// We only need to trace parameters which have an innermost JSVAL.
|
||||
if (param.type.InnermostType().Tag() != nsXPTType::T_JSVAL) {
|
||||
if (!param.DoesValNeedCleanup()) {
|
||||
MOZ_ASSERT(param.type.Tag() != nsXPTType::T_JSVAL,
|
||||
"JSVals are marked as needing cleanup (even though they don't)");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1963,6 +1963,31 @@ public:
|
|||
// for the WN case. You probably want UnwrapReflectorToISupports.
|
||||
static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface);
|
||||
|
||||
/**
|
||||
* Convert a native array into a JS::Value.
|
||||
*
|
||||
* @param d [out] the resulting JS::Value
|
||||
* @param s the native array we're working with
|
||||
* @param type the type of objects in the array
|
||||
* @param iid the interface of each object in the array that we want
|
||||
* @param count the number of items in the array
|
||||
* @param scope the default scope to put on the new JSObjects' parent chain
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static bool NativeArray2JS(JS::MutableHandleValue d, const void* const* s,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr);
|
||||
|
||||
static bool JSArray2Native(void** d, JS::HandleValue s,
|
||||
uint32_t count, const nsXPTType& type,
|
||||
const nsID* iid, nsresult* pErr);
|
||||
|
||||
static bool JSTypedArray2Native(void** d,
|
||||
JSObject* jsarray,
|
||||
uint32_t count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr);
|
||||
|
||||
static nsresult JSValToXPCException(JS::MutableHandleValue s,
|
||||
const char* ifaceName,
|
||||
const char* methodName,
|
||||
|
@ -1977,40 +2002,6 @@ public:
|
|||
JS::Value* jsExceptionPtr);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Convert a native array into a JS::Value.
|
||||
*
|
||||
* @param d [out] the resulting JS::Value
|
||||
* @param buf the native buffer containing input values
|
||||
* @param type the type of objects in the array
|
||||
* @param iid the interface of each object in the array that we want
|
||||
* @param count the number of items in the array
|
||||
* @param scope the default scope to put on the new JSObjects' parent chain
|
||||
* @param pErr [out] relevant error code, if any.
|
||||
*/
|
||||
static bool NativeArray2JS(JS::MutableHandleValue d, const void* buf,
|
||||
const nsXPTType& type, const nsID* iid,
|
||||
uint32_t count, nsresult* pErr);
|
||||
|
||||
typedef std::function<void* (uint32_t*)> ArrayAllocFixupLen;
|
||||
|
||||
/**
|
||||
* Convert a JS::Value into a native array.
|
||||
*
|
||||
* @param aJSVal the JS::Value to convert
|
||||
* @param aEltType the type of objects in the array
|
||||
* @param aIID the interface of each object in the array
|
||||
* @param pErr [out] relevant error code, if any
|
||||
* @param aAllocFixupLen function called with the JS Array's length to
|
||||
* allocate the backing buffer. This function may
|
||||
* modify the length of array to be converted.
|
||||
*/
|
||||
static bool JSArray2Native(JS::HandleValue aJSVal,
|
||||
const nsXPTType& aEltType,
|
||||
const nsIID* aIID,
|
||||
nsresult* pErr,
|
||||
const ArrayAllocFixupLen& aAllocFixupLen);
|
||||
|
||||
XPCConvert() = delete;
|
||||
|
||||
};
|
||||
|
@ -3048,7 +3039,7 @@ nsIPrincipal* GetObjectPrincipal(JSObject* obj);
|
|||
// value : char[16_t]** (free)
|
||||
// TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE
|
||||
// value : nsISupports** (release)
|
||||
// TD_LEGACY_ARRAY (NOTE: aArrayLen should be passed)
|
||||
// TD_ARRAY (NOTE: aArrayLen should be passed)
|
||||
// value : void** (cleanup elements & free)
|
||||
// TD_DOMOBJECT
|
||||
// value : T** (cleanup)
|
||||
|
@ -3069,17 +3060,6 @@ void InnerCleanupValue(const nsXPTType& aType,
|
|||
void* aValue,
|
||||
uint32_t aArrayLen);
|
||||
|
||||
// In order to be able to safely call CleanupValue on a generated value, the
|
||||
// data behind it needs to be initialized to a safe value. This method handles
|
||||
// initializing the backing data to a safe value to use as an argument to
|
||||
// XPCConvert methods, or xpc::CleanupValue.
|
||||
//
|
||||
// The pointer `aValue` must point to a block of memory at least aType.Stride()
|
||||
// bytes large, and correctly aligned.
|
||||
//
|
||||
// This method accepts the same types as xpc::CleanupValue.
|
||||
void InitializeValue(const nsXPTType& aType, void* aValue);
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -64,19 +64,11 @@ TestParams.prototype = {
|
|||
testAUTF8String: f,
|
||||
testACString: f,
|
||||
testJsval: f,
|
||||
testShortSequence: f,
|
||||
testDoubleSequence: f,
|
||||
testAStringSequence: f,
|
||||
testACStringSequence: f,
|
||||
testInterfaceSequence: f,
|
||||
testJsvalSequence: f,
|
||||
testInterfaceIsSequence: f_is,
|
||||
testShortArray: f_is,
|
||||
testDoubleArray: f_is,
|
||||
testStringArray: f_is,
|
||||
testWstringArray: f_is,
|
||||
testInterfaceArray: f_is,
|
||||
testJsvalArray: f_is,
|
||||
testSizedString: f_is,
|
||||
testSizedWstring: f_is,
|
||||
testInterfaceIs: f_is,
|
||||
|
|
|
@ -28,14 +28,6 @@ nsXPCTestParams::~nsXPCTestParams()
|
|||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP) { \
|
||||
_retval.SwapElements(b); \
|
||||
b = a; \
|
||||
for (uint32_t i = 0; i < b.Length(); ++i) \
|
||||
TAKE_OWNERSHIP(b[i]); \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define TAKE_OWNERSHIP_NOOP(val) {}
|
||||
#define TAKE_OWNERSHIP_INTERFACE(val) {static_cast<nsISupports*>(val)->AddRef();}
|
||||
#define TAKE_OWNERSHIP_STRING(val) { \
|
||||
|
@ -231,13 +223,6 @@ NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray(uint32_t aLength, nsIXPCTestIn
|
|||
BUFFER_METHOD_IMPL(nsIXPCTestInterfaceA*, 0, TAKE_OWNERSHIP_INTERFACE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXPCTestParams::TestJsvalArray(uint32_t aLength, JS::Value *a,
|
||||
uint32_t* bLength, JS::Value **b,
|
||||
uint32_t* rvLength, JS::Value **rv)
|
||||
{
|
||||
BUFFER_METHOD_IMPL(JS::Value, 0, TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char * a,
|
||||
uint32_t* bLength, char * *b,
|
||||
uint32_t* rvLength, char * *rv)
|
||||
|
@ -321,68 +306,3 @@ NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char * *a, uint
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestShortSequence(const nsTArray<short>& a, nsTArray<short>& b, nsTArray<short>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestDoubleSequence(const nsTArray<double>& a, nsTArray<double>& b, nsTArray<double>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestInterfaceSequence(const nsTArray<RefPtr<nsIXPCTestInterfaceA>>& a,
|
||||
nsTArray<RefPtr<nsIXPCTestInterfaceA>>& b,
|
||||
nsTArray<RefPtr<nsIXPCTestInterfaceA>>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestAStringSequence(const nsTArray<nsString>& a,
|
||||
nsTArray<nsString>& b,
|
||||
nsTArray<nsString>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestACStringSequence(const nsTArray<nsCString>& a,
|
||||
nsTArray<nsCString>& b,
|
||||
nsTArray<nsCString>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestJsvalSequence(const nsTArray<JS::Value>& a,
|
||||
nsTArray<JS::Value>& b,
|
||||
nsTArray<JS::Value>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestSequenceSequence(const nsTArray<nsTArray<short>>& a,
|
||||
nsTArray<nsTArray<short>>& b,
|
||||
nsTArray<nsTArray<short>>& _retval)
|
||||
{
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCTestParams::TestInterfaceIsSequence(const nsIID* aIID, const nsTArray<void*>& a,
|
||||
nsIID** bIID, nsTArray<void*>& b,
|
||||
nsIID** rvIID, nsTArray<void*>& _retval)
|
||||
{
|
||||
// Shuffle around our nsIIDs
|
||||
*rvIID = (*bIID)->Clone();
|
||||
*bIID = aIID->Clone();
|
||||
|
||||
// Perform the generic sequence shuffle.
|
||||
SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_INTERFACE);
|
||||
}
|
||||
|
|
|
@ -39,19 +39,6 @@ interface nsIXPCTestParams : nsISupports {
|
|||
ACString testACString(in ACString a, inout ACString b);
|
||||
jsval testJsval(in jsval a, inout jsval b);
|
||||
|
||||
// Test various forms of the Array<T> type.
|
||||
Array<short> testShortSequence(in Array<short> a, inout Array<short> b);
|
||||
Array<double> testDoubleSequence(in Array<double> a, inout Array<double> b);
|
||||
Array<nsIXPCTestInterfaceA> testInterfaceSequence(in Array<nsIXPCTestInterfaceA> a, inout Array<nsIXPCTestInterfaceA> b);
|
||||
Array<AString> testAStringSequence(in Array<AString> a, inout Array<AString> b);
|
||||
Array<ACString> testACStringSequence(in Array<ACString> a, inout Array<ACString> b);
|
||||
Array<jsval> testJsvalSequence(in Array<jsval> a, inout Array<jsval> b);
|
||||
Array<Array<short> > testSequenceSequence(in Array<Array<short> > a, inout Array<Array<short> > b);
|
||||
|
||||
void testInterfaceIsSequence(in nsIIDPtr aIID, [iid_is(aIID)] in Array<nsQIResult> a,
|
||||
inout nsIIDPtr bIID, [iid_is(bIID)] inout Array<nsQIResult> b,
|
||||
out nsIIDPtr rvIID, [retval, iid_is(rvIID)] out Array<nsQIResult> rv);
|
||||
|
||||
//
|
||||
// Dependent parameters use the same types as above, but are handled much differently.
|
||||
//
|
||||
|
@ -95,12 +82,6 @@ interface nsIXPCTestParams : nsISupports {
|
|||
out unsigned long rvLength, out nsIIDPtr rvIID,
|
||||
[retval, array, size_is(rvLength), iid_is(rvIID)] out nsQIResult rv);
|
||||
|
||||
// Test arrays of jsvals
|
||||
void testJsvalArray(in unsigned long aLength, [array, size_is(aLength)] in jsval a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout jsval b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out jsval rv);
|
||||
|
||||
|
||||
// Test for out dipper parameters
|
||||
void testOutAString(out AString o);
|
||||
|
||||
|
|
|
@ -163,8 +163,6 @@ function test_component(contractid) {
|
|||
["we", "are", "being", "sooo", "international", "right", "now"], 7, arrayComparator(standardComparator));
|
||||
doIsTest("testInterfaceArray", [makeA(), makeA()], 2,
|
||||
[makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], 6, arrayComparator(interfaceComparator));
|
||||
doIsTest("testJsvalArray", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/], 3,
|
||||
['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], 4, arrayComparator(standardComparator));
|
||||
|
||||
// Test typed arrays and ArrayBuffer aliasing.
|
||||
var arrayBuffer = new ArrayBuffer(16);
|
||||
|
@ -197,24 +195,4 @@ function test_component(contractid) {
|
|||
// Test type mismatch (int16 <-> uint16); this should throw BAD_CONVERT_JS.
|
||||
doTypedArrayMismatchTest("testShortArray", new Uint16Array([0, 7, 4, 3]), 4,
|
||||
new Uint16Array([1, 5, 6]), 3);
|
||||
|
||||
// Test Sequence<T> types.
|
||||
doTest("testShortSequence", [2, 4, 6], [1, 3, 5, 7], arrayComparator(standardComparator));
|
||||
doTest("testDoubleSequence", [-10, -0.5], [1, 3, 1e11, -8e-5 ], arrayComparator(fuzzComparator));
|
||||
doTest("testACStringSequence", ["mary", "hat", "hey", "lid", "tell", "lam"],
|
||||
["ids", "fleas", "woes", "wide", "has", "know", "!"],
|
||||
arrayComparator(standardComparator));
|
||||
doTest("testAStringSequence", ["沒有語言", "的偉大嗎?]"],
|
||||
["we", "are", "being", "sooo", "international", "right", "now"],
|
||||
arrayComparator(standardComparator));
|
||||
|
||||
doTest("testInterfaceSequence", [makeA(), makeA()],
|
||||
[makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], arrayComparator(interfaceComparator));
|
||||
|
||||
doTest("testJsvalSequence", [{ cheese: 'whiz', apple: 8 }, [1, 5, '3'], /regex/],
|
||||
['apple', 2.2e10, 3.3e30, { only: "wheedle", except: {} }], arrayComparator(standardComparator));
|
||||
|
||||
doIsTest("testInterfaceIsSequence", [makeA(), makeA(), makeA(), makeA(), makeA()], Ci['nsIXPCTestInterfaceA'],
|
||||
[makeB(), makeB(), makeB()], Ci['nsIXPCTestInterfaceB'],
|
||||
arrayComparator(interfaceComparator), dotEqualsComparator);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ struct nsIDataType
|
|||
VTYPE_WCHAR_STR = TD_PWSTRING ,
|
||||
VTYPE_INTERFACE = TD_INTERFACE_TYPE ,
|
||||
VTYPE_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
|
||||
VTYPE_ARRAY = TD_LEGACY_ARRAY ,
|
||||
VTYPE_ARRAY = TD_ARRAY ,
|
||||
VTYPE_STRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
|
||||
VTYPE_WSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
|
||||
VTYPE_UTF8STRING = TD_UTF8STRING ,
|
||||
|
|
|
@ -2550,13 +2550,6 @@ public:
|
|||
this->AppendElements(aOther);
|
||||
}
|
||||
|
||||
AutoTArray(self_type&& aOther)
|
||||
: nsTArray<E>()
|
||||
{
|
||||
Init();
|
||||
this->SwapElements(aOther);
|
||||
}
|
||||
|
||||
explicit AutoTArray(const base_type& aOther)
|
||||
: mAlign()
|
||||
{
|
||||
|
@ -2591,12 +2584,6 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
self_type& operator=(self_type&& aOther)
|
||||
{
|
||||
base_type::operator=(std::move(aOther));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& aOther)
|
||||
{
|
||||
|
|
|
@ -63,18 +63,10 @@ def get_type(type, calltype, iid_is=None, size_is=None):
|
|||
return ret
|
||||
|
||||
if isinstance(type, xpidl.Array):
|
||||
# NB: For a Array<T> we pass down the iid_is to get the type of T.
|
||||
# NB: For an Array<T> we pass down the iid_is to get the type of T.
|
||||
# This allows Arrays of InterfaceIs types to work.
|
||||
return {
|
||||
'tag': 'TD_ARRAY',
|
||||
'element': get_type(type.type, calltype, iid_is),
|
||||
}
|
||||
|
||||
if isinstance(type, xpidl.LegacyArray):
|
||||
# NB: For a Legacy [array] T we pass down iid_is to get the type of T.
|
||||
# This allows [array] of InterfaceIs types to work.
|
||||
return {
|
||||
'tag': 'TD_LEGACY_ARRAY',
|
||||
'size_is': size_is,
|
||||
'element': get_type(type.type, calltype, iid_is),
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ void bar();
|
|||
m = iface.members[0]
|
||||
self.assertTrue(isinstance(m, xpidl.Method))
|
||||
self.assertEqual("bar", m.name)
|
||||
self.assertEqual(xpidl.TypeId("void"), m.type)
|
||||
self.assertEqual("void", m.type)
|
||||
|
||||
def testMethodParams(self):
|
||||
i = self.p.parse("""[uuid(abc)] interface foo {
|
||||
|
@ -73,15 +73,15 @@ long bar(in long a, in float b, [array] in long c);
|
|||
m = iface.members[0]
|
||||
self.assertTrue(isinstance(m, xpidl.Method))
|
||||
self.assertEqual("bar", m.name)
|
||||
self.assertEqual(xpidl.TypeId("long"), m.type)
|
||||
self.assertEqual("long", m.type)
|
||||
self.assertEqual(3, len(m.params))
|
||||
self.assertEqual(xpidl.TypeId("long"), m.params[0].type)
|
||||
self.assertEqual("long", m.params[0].type)
|
||||
self.assertEqual("in", m.params[0].paramtype)
|
||||
self.assertEqual(xpidl.TypeId("float"), m.params[1].type)
|
||||
self.assertEqual("float", m.params[1].type)
|
||||
self.assertEqual("in", m.params[1].paramtype)
|
||||
self.assertEqual(xpidl.TypeId("long"), m.params[2].type)
|
||||
self.assertEqual("long", m.params[2].type)
|
||||
self.assertEqual("in", m.params[2].paramtype)
|
||||
self.assertTrue(isinstance(m.params[2].realtype, xpidl.LegacyArray))
|
||||
self.assertTrue(isinstance(m.params[2].realtype, xpidl.Array))
|
||||
self.assertEqual("long", m.params[2].realtype.type.name)
|
||||
|
||||
def testAttribute(self):
|
||||
|
@ -94,7 +94,7 @@ attribute long bar;
|
|||
a = iface.members[0]
|
||||
self.assertTrue(isinstance(a, xpidl.Attribute))
|
||||
self.assertEqual("bar", a.name)
|
||||
self.assertEqual(xpidl.TypeId("long"), a.type)
|
||||
self.assertEqual("long", a.type)
|
||||
|
||||
def testOverloadedVirtual(self):
|
||||
i = self.p.parse("""[uuid(abc)] interface foo {
|
||||
|
|
|
@ -12,7 +12,6 @@ import os.path
|
|||
import re
|
||||
from ply import lex
|
||||
from ply import yacc
|
||||
from collections import namedtuple
|
||||
|
||||
"""A type conforms to the following pattern:
|
||||
|
||||
|
@ -21,7 +20,7 @@ from collections import namedtuple
|
|||
|
||||
def nativeType(self, calltype):
|
||||
'returns a string representation of the native type
|
||||
calltype must be 'in', 'out', 'inout', or 'element'
|
||||
calltype must be 'in', 'out', or 'inout'
|
||||
|
||||
Interface members const/method/attribute conform to the following pattern:
|
||||
|
||||
|
@ -132,9 +131,6 @@ class Builtin(object):
|
|||
return self.nativename.endswith('*')
|
||||
|
||||
def nativeType(self, calltype, shared=False, const=False):
|
||||
if self.name in ["string", "wstring"] and calltype == 'element':
|
||||
raise IDLError("Use string class types for string Array elements", self.location)
|
||||
|
||||
if const:
|
||||
print >>sys.stderr, IDLError(
|
||||
"[const] doesn't make sense on builtin types.", self.location, warning=True)
|
||||
|
@ -148,7 +144,7 @@ class Builtin(object):
|
|||
else:
|
||||
const = ''
|
||||
return "%s%s %s" % (const, self.nativename,
|
||||
'*' if 'out' in calltype else '')
|
||||
calltype != 'in' and '*' or '')
|
||||
|
||||
def rustType(self, calltype, shared=False, const=False):
|
||||
# We want to rewrite any *mut pointers to *const pointers if constness
|
||||
|
@ -325,7 +321,6 @@ class Include(object):
|
|||
|
||||
class IDL(object):
|
||||
def __init__(self, productions):
|
||||
self.hasSequence = False
|
||||
self.productions = productions
|
||||
self.deps = []
|
||||
|
||||
|
@ -333,19 +328,10 @@ class IDL(object):
|
|||
self.namemap.set(object)
|
||||
|
||||
def getName(self, id, location):
|
||||
if id.name == 'Array':
|
||||
if id.params is None or len(id.params) != 1:
|
||||
raise IDLError("Array takes exactly 1 parameter", location)
|
||||
self.hasSequence = True
|
||||
return Array(self.getName(id.params[0], location), location)
|
||||
|
||||
if id.params is not None:
|
||||
raise IDLError("Generic type '%s' unrecognized" % id.name, location)
|
||||
|
||||
try:
|
||||
return self.namemap[id.name]
|
||||
return self.namemap[id]
|
||||
except KeyError:
|
||||
raise IDLError("type '%s' not found" % id.name, location)
|
||||
raise IDLError("type '%s' not found" % id, location)
|
||||
|
||||
def hasName(self, id):
|
||||
return id in self.namemap
|
||||
|
@ -368,8 +354,6 @@ class IDL(object):
|
|||
for p in self.productions:
|
||||
if p.kind == 'include':
|
||||
yield p
|
||||
if self.hasSequence:
|
||||
yield Include("nsTArray.h", BuiltinLocation)
|
||||
|
||||
def needsJSTypes(self):
|
||||
for p in self.productions:
|
||||
|
@ -412,14 +396,12 @@ class Typedef(object):
|
|||
parent.setName(self)
|
||||
self.realtype = parent.getName(self.type, self.location)
|
||||
|
||||
if not isinstance(self.realtype, (Builtin, Native, Typedef)):
|
||||
raise IDLError("Unsupported typedef target type", self.location)
|
||||
|
||||
def isScriptable(self):
|
||||
return self.realtype.isScriptable()
|
||||
|
||||
def nativeType(self, calltype):
|
||||
return "%s %s" % (self.name, '*' if 'out' in calltype else '')
|
||||
return "%s %s" % (self.name,
|
||||
calltype != 'in' and '*' or '')
|
||||
|
||||
def rustType(self, calltype):
|
||||
return "%s%s" % (calltype != 'in' and '*mut ' or '',
|
||||
|
@ -458,9 +440,8 @@ class Forward(object):
|
|||
return True
|
||||
|
||||
def nativeType(self, calltype):
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.name
|
||||
return "%s *%s" % (self.name, '*' if 'out' in calltype else '')
|
||||
return "%s %s" % (self.name,
|
||||
calltype != 'in' and '* *' or '*')
|
||||
|
||||
def rustType(self, calltype):
|
||||
if rustBlacklistedForward(self.name):
|
||||
|
@ -478,19 +459,29 @@ class Native(object):
|
|||
modifier = None
|
||||
specialtype = None
|
||||
|
||||
# A tuple type here means that a custom value is used for each calltype:
|
||||
# (in, out/inout, array element) respectively.
|
||||
# A `None` here means that the written type should be used as-is.
|
||||
specialtypes = {
|
||||
'nsid': None,
|
||||
'domstring': ('const nsAString&', 'nsAString&', 'nsString'),
|
||||
'utf8string': ('const nsACString&', 'nsACString&', 'nsCString'),
|
||||
'cstring': ('const nsACString&', 'nsACString&', 'nsCString'),
|
||||
'astring': ('const nsAString&', 'nsAString&', 'nsString'),
|
||||
'jsval': ('JS::HandleValue', 'JS::MutableHandleValue', 'JS::Value'),
|
||||
'domstring': 'nsAString',
|
||||
'utf8string': 'nsACString',
|
||||
'cstring': 'nsACString',
|
||||
'astring': 'nsAString',
|
||||
'jsval': 'JS::Value',
|
||||
'promise': '::mozilla::dom::Promise',
|
||||
}
|
||||
|
||||
# Mappings from C++ native name types to rust native names. Types which
|
||||
# aren't listed here are incompatible with rust code.
|
||||
rust_nativenames = {
|
||||
'void': "libc::c_void",
|
||||
'char': "u8",
|
||||
'char16_t': "u16",
|
||||
'nsID': "nsID",
|
||||
'nsIID': "nsIID",
|
||||
'nsCID': "nsCID",
|
||||
'nsAString': "::nsstring::nsAString",
|
||||
'nsACString': "::nsstring::nsACString",
|
||||
}
|
||||
|
||||
def __init__(self, name, nativename, attlist, location):
|
||||
self.name = name
|
||||
self.nativename = nativename
|
||||
|
@ -542,75 +533,47 @@ class Native(object):
|
|||
def nativeType(self, calltype, const=False, shared=False):
|
||||
if shared:
|
||||
if calltype != 'out':
|
||||
raise IDLError("[shared] only applies to out parameters.", self.location)
|
||||
raise IDLError("[shared] only applies to out parameters.")
|
||||
const = True
|
||||
|
||||
if isinstance(self.nativename, tuple):
|
||||
if calltype == 'in':
|
||||
return self.nativename[0] + ' '
|
||||
elif 'out' in calltype:
|
||||
return self.nativename[1] + ' '
|
||||
else:
|
||||
return self.nativename[2] + ' '
|
||||
|
||||
# 'in' nsid parameters should be made 'const'
|
||||
if self.specialtype == 'nsid' and calltype == 'in':
|
||||
if self.specialtype not in [None, 'promise'] and calltype == 'in':
|
||||
const = True
|
||||
|
||||
if calltype == 'element':
|
||||
if self.isRef(calltype):
|
||||
raise IDLError("[ref] qualified type unsupported in Array<T>", self.location)
|
||||
|
||||
# Promises should be held in RefPtr<T> in Array<T>s
|
||||
if self.specialtype == 'promise':
|
||||
return 'RefPtr<mozilla::dom::Promise>'
|
||||
|
||||
# We don't support nsIDPtr, in Array<T> currently, although
|
||||
# this or support for Array<nsID> will be needed to replace
|
||||
# [array] completely.
|
||||
if self.specialtype == 'nsid':
|
||||
raise IDLError("Array<nsIDPtr> not yet supported. "
|
||||
"File an XPConnect bug if you need it.", self.location)
|
||||
if self.specialtype == 'jsval':
|
||||
if calltype == 'out' or calltype == 'inout':
|
||||
return "JS::MutableHandleValue "
|
||||
return "JS::HandleValue "
|
||||
|
||||
if self.isRef(calltype):
|
||||
m = '& ' # [ref] is always passed with a single indirection
|
||||
m = '& '
|
||||
elif self.isPtr(calltype):
|
||||
m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
|
||||
else:
|
||||
m = '* ' if 'out' in calltype else ''
|
||||
if self.isPtr(calltype):
|
||||
m += '* '
|
||||
m = calltype != 'in' and '*' or ''
|
||||
return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
|
||||
|
||||
def rustType(self, calltype, const=False, shared=False):
|
||||
# For the most part, 'native' types don't make sense in rust, as they
|
||||
# are native C++ types. However, we can support a few types here, as
|
||||
# they're important.
|
||||
#
|
||||
# NOTE: This code doesn't try to perfectly match C++ constness, as
|
||||
# constness doesn't affect ABI, and raw pointers are already unsafe.
|
||||
if shared:
|
||||
if calltype != 'out':
|
||||
raise IDLError("[shared] only applies to out parameters.")
|
||||
const = True
|
||||
|
||||
if self.modifier not in ['ptr', 'ref']:
|
||||
raise RustNoncompat('Rust only supports [ref] / [ptr] native types')
|
||||
if self.specialtype is not None and calltype == 'in':
|
||||
const = True
|
||||
|
||||
prefix = '*mut ' if 'out' in calltype else '*const '
|
||||
if 'out' in calltype and self.modifier == 'ptr':
|
||||
prefix += '*mut '
|
||||
if self.nativename not in self.rust_nativenames:
|
||||
raise RustNoncompat("native type %s is unsupported" % self.nativename)
|
||||
name = self.rust_nativenames[self.nativename]
|
||||
|
||||
if self.specialtype == 'nsid':
|
||||
return prefix + self.nativename
|
||||
if self.specialtype in ['cstring', 'utf8string']:
|
||||
if 'element' in calltype:
|
||||
return '::nsstring::nsCString'
|
||||
return prefix + '::nsstring::nsACString'
|
||||
if self.specialtype in ['astring', 'domstring']:
|
||||
if 'element' in calltype:
|
||||
return '::nsstring::nsString'
|
||||
return prefix + '::nsstring::nsAString'
|
||||
if self.nativename == 'void':
|
||||
return prefix + 'libc::c_void'
|
||||
|
||||
if self.specialtype:
|
||||
raise RustNoncompat("specialtype %s unsupported" % self.specialtype)
|
||||
raise RustNoncompat("native type %s unsupported" % self.nativename)
|
||||
if self.isRef(calltype):
|
||||
m = const and '&' or '&mut '
|
||||
elif self.isPtr(calltype):
|
||||
m = (const and '*const ' or '*mut ')
|
||||
if self.modifier == 'ptr' and calltype != 'in':
|
||||
m += '*mut '
|
||||
else:
|
||||
m = calltype != 'in' and '*mut ' or ''
|
||||
return "%s%s" % (m, name)
|
||||
|
||||
def __str__(self):
|
||||
return "native %s(%s)\n" % (self.name, self.nativename)
|
||||
|
@ -650,13 +613,11 @@ class WebIDL(object):
|
|||
return True # All DOM objects are script exposed.
|
||||
|
||||
def nativeType(self, calltype):
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.native
|
||||
return "%s *%s" % (self.native, '*' if 'out' in calltype else '')
|
||||
return "%s %s" % (self.native, calltype != 'in' and '* *' or '*')
|
||||
|
||||
def rustType(self, calltype):
|
||||
# Just expose the type as a void* - we can't do any better.
|
||||
return "%s*const libc::c_void" % ('*mut ' if 'out' in calltype else '')
|
||||
return "%s*const libc::c_void" % (calltype != 'in' and '*mut ' or '')
|
||||
|
||||
def __str__(self):
|
||||
return "webidl %s\n" % self.name
|
||||
|
@ -701,7 +662,7 @@ class Interface(object):
|
|||
if hasattr(member, 'doccomments'):
|
||||
member.doccomments[0:0] = self.doccomments
|
||||
break
|
||||
self.doccomments = parent.getName(TypeId(self.name), None).doccomments
|
||||
self.doccomments = parent.getName(self.name, None).doccomments
|
||||
|
||||
if self.attributes.function:
|
||||
has_method = False
|
||||
|
@ -716,7 +677,7 @@ class Interface(object):
|
|||
|
||||
parent.setName(self)
|
||||
if self.base is not None:
|
||||
realbase = parent.getName(TypeId(self.base), self.location)
|
||||
realbase = parent.getName(self.base, self.location)
|
||||
if realbase.kind != 'interface':
|
||||
raise IDLError("interface '%s' inherits from non-interface type '%s'" %
|
||||
(self.name, self.base), self.location)
|
||||
|
@ -752,13 +713,12 @@ class Interface(object):
|
|||
return True
|
||||
|
||||
def nativeType(self, calltype, const=False):
|
||||
if calltype == 'element':
|
||||
return 'RefPtr<%s>' % self.name
|
||||
return "%s%s *%s" % ('const ' if const else '', self.name,
|
||||
'*' if 'out' in calltype else '')
|
||||
return "%s%s %s" % (const and 'const ' or '',
|
||||
self.name,
|
||||
calltype != 'in' and '* *' or '*')
|
||||
|
||||
def rustType(self, calltype, const=False):
|
||||
return "%s*const %s" % ('*mut ' if 'out' in calltype else '',
|
||||
def rustType(self, calltype):
|
||||
return "%s*const %s" % (calltype != 'in' and '*mut ' or '',
|
||||
self.name)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -777,9 +737,9 @@ class Interface(object):
|
|||
# The constant may be in a base class
|
||||
iface = self
|
||||
while name not in iface.namemap and iface is not None:
|
||||
iface = self.idl.getName(TypeId(self.base), self.location)
|
||||
iface = self.idl.getName(self.base, self.location)
|
||||
if iface is None:
|
||||
raise IDLError("cannot find symbol '%s'" % name, self.location)
|
||||
raise IDLError("cannot find symbol '%s'" % name)
|
||||
c = iface.namemap.get(name, location)
|
||||
if c.kind != 'const':
|
||||
raise IDLError("symbol '%s' is not a constant", c.location)
|
||||
|
@ -788,7 +748,7 @@ class Interface(object):
|
|||
|
||||
def needsJSTypes(self):
|
||||
for m in self.members:
|
||||
if m.kind == "attribute" and m.type == TypeId("jsval"):
|
||||
if m.kind == "attribute" and m.type == "jsval":
|
||||
return True
|
||||
if m.kind == "method" and m.needsJSTypes():
|
||||
return True
|
||||
|
@ -798,7 +758,7 @@ class Interface(object):
|
|||
''' Returns the number of entries in the vtable for this interface. '''
|
||||
total = sum(member.count() for member in self.members)
|
||||
if self.base is not None:
|
||||
realbase = self.idl.getName(TypeId(self.base), self.location)
|
||||
realbase = self.idl.getName(self.base, self.location)
|
||||
total += realbase.countEntries()
|
||||
return total
|
||||
|
||||
|
@ -1124,7 +1084,7 @@ class Method(object):
|
|||
def needsJSTypes(self):
|
||||
if self.implicit_jscontext:
|
||||
return True
|
||||
if self.type == TypeId("jsval"):
|
||||
if self.type == "jsval":
|
||||
return True
|
||||
for p in self.params:
|
||||
t = p.realtype
|
||||
|
@ -1206,7 +1166,7 @@ class Param(object):
|
|||
def resolve(self, method):
|
||||
self.realtype = method.iface.idl.getName(self.type, self.location)
|
||||
if self.array:
|
||||
self.realtype = LegacyArray(self.realtype)
|
||||
self.realtype = Array(self.realtype)
|
||||
if (self.null is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Null' attribute can only be used on DOMString",
|
||||
|
@ -1251,80 +1211,20 @@ class Param(object):
|
|||
self.name)
|
||||
|
||||
|
||||
class LegacyArray(object):
|
||||
class Array(object):
|
||||
def __init__(self, basetype):
|
||||
self.type = basetype
|
||||
self.location = self.type.location
|
||||
|
||||
def isScriptable(self):
|
||||
return self.type.isScriptable()
|
||||
|
||||
def nativeType(self, calltype, const=False):
|
||||
if 'element' in calltype:
|
||||
raise IDLError("nested [array] unsupported", self.location)
|
||||
|
||||
# For legacy reasons, we have to add a 'const ' to builtin pointer array
|
||||
# types. (`[array] in string` and `[array] in wstring` parameters)
|
||||
if calltype == 'in' and isinstance(self.type, Builtin) and self.type.isPointer():
|
||||
const = True
|
||||
|
||||
return "%s%s*%s" % ('const ' if const else '',
|
||||
self.type.nativeType('legacyelement'),
|
||||
'*' if 'out' in calltype else '')
|
||||
return "%s%s*" % (const and 'const ' or '',
|
||||
self.type.nativeType(calltype))
|
||||
|
||||
def rustType(self, calltype, const=False):
|
||||
return "%s%s%s" % ('*mut ' if 'out' in calltype else '',
|
||||
'*const ' if const else '*mut ',
|
||||
self.type.rustType('legacyelement'))
|
||||
|
||||
|
||||
class Array(object):
|
||||
kind = 'array'
|
||||
|
||||
def __init__(self, type, location):
|
||||
self.type = type
|
||||
self.location = location
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return "Array<%s>" % self.type.name
|
||||
|
||||
def resolve(self, idl):
|
||||
idl.getName(self.type, self.location)
|
||||
|
||||
def isScriptable(self):
|
||||
return self.type.isScriptable()
|
||||
|
||||
def nativeType(self, calltype):
|
||||
if calltype == 'legacyelement':
|
||||
raise IDLError("[array] Array<T> is unsupported", self.location)
|
||||
|
||||
base = 'nsTArray<%s>' % self.type.nativeType('element')
|
||||
if 'out' in calltype:
|
||||
return '%s& ' % base
|
||||
elif 'in' == calltype:
|
||||
return 'const %s& ' % base
|
||||
else:
|
||||
return base
|
||||
|
||||
def rustType(self, calltype):
|
||||
# NOTE: To add Rust support, ensure 'element' is handled correctly in
|
||||
# all rustType callees.
|
||||
raise RustNoncompat("Array<...> types")
|
||||
|
||||
|
||||
TypeId = namedtuple('TypeId', 'name params')
|
||||
|
||||
|
||||
# Make str(TypeId) produce a nicer value
|
||||
TypeId.__str__ = lambda self: \
|
||||
"%s<%s>" % (self.name, ', '.join(str(p) for p in self.params)) \
|
||||
if self.params is not None \
|
||||
else self.name
|
||||
|
||||
|
||||
# Allow skipping 'params' in TypeId(..)
|
||||
TypeId.__new__.__defaults__ = (None,)
|
||||
return "%s %s" % (const and '*const' or '*mut',
|
||||
self.type.rustType(calltype))
|
||||
|
||||
|
||||
class IDLParser(object):
|
||||
|
@ -1367,7 +1267,7 @@ class IDLParser(object):
|
|||
t_LSHIFT = r'<<'
|
||||
t_RSHIFT = r'>>'
|
||||
|
||||
literals = '"(){}[]<>,;:=|+-*'
|
||||
literals = '"(){}[],;:=|+-*'
|
||||
|
||||
t_ignore = ' \t'
|
||||
|
||||
|
@ -1460,7 +1360,7 @@ class IDLParser(object):
|
|||
p[0].insert(0, p[1])
|
||||
|
||||
def p_typedef(self, p):
|
||||
"""typedef : TYPEDEF type IDENTIFIER ';'"""
|
||||
"""typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'"""
|
||||
p[0] = Typedef(type=p[2],
|
||||
name=p[3],
|
||||
location=self.getLocation(p, 1),
|
||||
|
@ -1573,7 +1473,7 @@ class IDLParser(object):
|
|||
p[0] = CDATA(p[1], self.getLocation(p, 1))
|
||||
|
||||
def p_member_const(self, p):
|
||||
"""member : CONST type IDENTIFIER '=' number ';' """
|
||||
"""member : CONST IDENTIFIER IDENTIFIER '=' number ';' """
|
||||
p[0] = ConstMember(type=p[2], name=p[3],
|
||||
value=p[5], location=self.getLocation(p, 1),
|
||||
doccomments=p.slice[1].doccomments)
|
||||
|
@ -1635,7 +1535,7 @@ class IDLParser(object):
|
|||
p[0] = lambda i: n1(i) | n2(i)
|
||||
|
||||
def p_member_att(self, p):
|
||||
"""member : attributes optreadonly ATTRIBUTE type IDENTIFIER ';'"""
|
||||
"""member : attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'"""
|
||||
if 'doccomments' in p[1]:
|
||||
doccomments = p[1]['doccomments']
|
||||
elif p[2] is not None:
|
||||
|
@ -1651,7 +1551,7 @@ class IDLParser(object):
|
|||
doccomments=doccomments)
|
||||
|
||||
def p_member_method(self, p):
|
||||
"""member : attributes type IDENTIFIER '(' paramlist ')' raises ';'"""
|
||||
"""member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'"""
|
||||
if 'doccomments' in p[1]:
|
||||
doccomments = p[1]['doccomments']
|
||||
else:
|
||||
|
@ -1684,7 +1584,7 @@ class IDLParser(object):
|
|||
p[0].insert(0, p[2])
|
||||
|
||||
def p_param(self, p):
|
||||
"""param : attributes paramtype type IDENTIFIER"""
|
||||
"""param : attributes paramtype IDENTIFIER IDENTIFIER"""
|
||||
p[0] = Param(paramtype=p[2],
|
||||
type=p[3],
|
||||
name=p[4],
|
||||
|
@ -1722,25 +1622,6 @@ class IDLParser(object):
|
|||
p[0] = list(p[3])
|
||||
p[0].insert(0, p[1])
|
||||
|
||||
def p_type_id(self, p):
|
||||
"""type : IDENTIFIER"""
|
||||
p[0] = TypeId(name=p[1])
|
||||
p.slice[0].doccomments = p.slice[1].doccomments
|
||||
|
||||
def p_type_generic(self, p):
|
||||
"""type : IDENTIFIER '<' typelist '>'"""
|
||||
p[0] = TypeId(name=p[1], params=p[3])
|
||||
p.slice[0].doccomments = p.slice[1].doccomments
|
||||
|
||||
def p_typelist(self, p):
|
||||
"""typelist : type"""
|
||||
p[0] = [p[1]]
|
||||
|
||||
def p_typelist_continue(self, p):
|
||||
"""typelist : type ',' typelist"""
|
||||
p[0] = list(p[3])
|
||||
p[0].insert(0, p[1])
|
||||
|
||||
def p_error(self, t):
|
||||
if not t:
|
||||
raise IDLError(
|
||||
|
|
|
@ -31,8 +31,6 @@ invoke_count_words(uint32_t paramCount, nsXPTCVariant* s)
|
|||
case nsXPTType::T_DOUBLE :
|
||||
result++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -62,7 +60,6 @@ invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint32_t* d)
|
|||
case nsXPTType::T_I64 : *((int64_t*) d) = s->val.i64; d++; break;
|
||||
case nsXPTType::T_U64 : *((uint64_t*)d) = s->val.u64; d++; break;
|
||||
case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ PrepareAndDispatch(uint32_t methodIndex, nsXPTCStubBase* self, uint32_t* args)
|
|||
case nsXPTType::T_I64 : dp->val.i64 = *((int64_t*) ap); ap++; break;
|
||||
case nsXPTType::T_U64 : dp->val.u64 = *((uint64_t*)ap); ap++; break;
|
||||
case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
|
|||
case nsXPTType::T_I64 : dp->val.i64 = *((int64_t*) ap); ap++; break;
|
||||
case nsXPTType::T_U64 : dp->val.u64 = *((uint64_t*)ap); ap++; break;
|
||||
case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break;
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ static_assert(offsetof(nsXPTCMiniVariant, val) == 0,
|
|||
|
||||
struct nsXPTCVariant
|
||||
{
|
||||
// No ctors or dtors so that we can use arrays of these on the stack with no
|
||||
// penalty.
|
||||
union ExtendedVal
|
||||
{
|
||||
// ExtendedVal is an extension on nsXPTCMiniVariant. It contains types
|
||||
|
@ -58,7 +60,6 @@ struct nsXPTCVariant
|
|||
nsCString nscstr;
|
||||
nsString nsstr;
|
||||
JS::Value jsval;
|
||||
xpt::detail::UntypedTArray array;
|
||||
|
||||
// This type contains non-standard-layout types, so needs an explicit
|
||||
// Ctor/Dtor - we'll just delete them.
|
||||
|
@ -78,12 +79,6 @@ struct nsXPTCVariant
|
|||
nsXPTType type;
|
||||
uint8_t flags;
|
||||
|
||||
// Clear to a valid, null state.
|
||||
nsXPTCVariant() {
|
||||
memset(this, 0, sizeof(nsXPTCVariant));
|
||||
type = nsXPTType::T_VOID;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
//
|
||||
|
@ -93,12 +88,22 @@ struct nsXPTCVariant
|
|||
// Indicates that we &val.p should be passed n the stack, i.e. that
|
||||
// val should be passed by reference.
|
||||
IS_INDIRECT = 0x1,
|
||||
|
||||
// Indicates that the value we hold requires some sort of cleanup (memory
|
||||
// deallocation, interface release, JS::Value unrooting, etc). The precise
|
||||
// cleanup that is performed depends on the 'type' field above.
|
||||
// If the value is an array, this flag specifies whether the elements
|
||||
// within the array require cleanup (we always clean up the array itself,
|
||||
// so this flag would be redundant for that purpose).
|
||||
VAL_NEEDS_CLEANUP = 0x2
|
||||
};
|
||||
|
||||
void ClearFlags() {flags = 0;}
|
||||
void SetIndirect() {flags |= IS_INDIRECT;}
|
||||
void SetValNeedsCleanup() {flags |= VAL_NEEDS_CLEANUP;}
|
||||
|
||||
bool IsIndirect() const {return 0 != (flags & IS_INDIRECT);}
|
||||
bool DoesValNeedCleanup() const {return 0 != (flags & VAL_NEEDS_CLEANUP);}
|
||||
|
||||
// Implicitly convert to nsXPTCMiniVariant.
|
||||
operator nsXPTCMiniVariant&() {
|
||||
|
@ -108,8 +113,9 @@ struct nsXPTCVariant
|
|||
return *(const nsXPTCMiniVariant*) &val;
|
||||
}
|
||||
|
||||
// As this type contains an anonymous union, we need to provide an explicit
|
||||
// destructor.
|
||||
// As this type contains an anonymous union, we need to provide explicit
|
||||
// constructors & destructors.
|
||||
nsXPTCVariant() { }
|
||||
~nsXPTCVariant() { }
|
||||
};
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ def link_to_cpp(interfaces, fd):
|
|||
|
||||
def describe_type(type): # Create the type's documentation comment.
|
||||
tag = type['tag'][3:].lower()
|
||||
if tag == 'legacy_array':
|
||||
if tag == 'array':
|
||||
return '%s[size_is=%d]' % (
|
||||
describe_type(type['element']), type['size_is'])
|
||||
elif tag == 'interface_type' or tag == 'domobject':
|
||||
|
@ -280,15 +280,10 @@ def link_to_cpp(interfaces, fd):
|
|||
tag = type['tag']
|
||||
d1 = d2 = 0
|
||||
|
||||
if tag == 'TD_LEGACY_ARRAY':
|
||||
if tag == 'TD_ARRAY':
|
||||
d1 = type['size_is']
|
||||
d2 = lower_extra_type(type['element'])
|
||||
|
||||
elif tag == 'TD_ARRAY':
|
||||
# NOTE: TD_ARRAY can hold 16 bits of type index, while
|
||||
# TD_LEGACY_ARRAY can only hold 8.
|
||||
d1, d2 = splitint(lower_extra_type(type['element']))
|
||||
|
||||
elif tag == 'TD_INTERFACE_TYPE':
|
||||
d1, d2 = splitint(interface_idx(type['name']))
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "js/Value.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// Forward Declarations
|
||||
namespace mozilla {
|
||||
|
@ -153,14 +152,6 @@ static_assert(sizeof(nsXPTInterfaceInfo) == 28, "wrong size?");
|
|||
*/
|
||||
enum nsXPTTypeTag : uint8_t
|
||||
{
|
||||
// Arithmetic (POD) Types
|
||||
// - Do not require cleanup,
|
||||
// - All bit patterns are valid,
|
||||
// - Outparams may be uninitialized by caller,
|
||||
// - Directly supported in xptcall.
|
||||
//
|
||||
// NOTE: The name 'Arithmetic' comes from Harbison/Steele. Despite being a tad
|
||||
// unclear, it is used frequently in xptcall, so is unlikely to be changed.
|
||||
TD_INT8 = 0,
|
||||
TD_INT16 = 1,
|
||||
TD_INT32 = 2,
|
||||
|
@ -174,42 +165,24 @@ enum nsXPTTypeTag : uint8_t
|
|||
TD_BOOL = 10,
|
||||
TD_CHAR = 11,
|
||||
TD_WCHAR = 12,
|
||||
_TD_LAST_ARITHMETIC = TD_WCHAR,
|
||||
|
||||
// Pointer Types
|
||||
// - Require cleanup unless NULL,
|
||||
// - All-zeros (NULL) bit pattern is valid,
|
||||
// - Outparams may be uninitialized by caller,
|
||||
// - Supported in xptcall as raw pointer.
|
||||
TD_VOID = 13,
|
||||
TD_PNSIID = 14,
|
||||
TD_PSTRING = 15,
|
||||
TD_PWSTRING = 16,
|
||||
TD_INTERFACE_TYPE = 17,
|
||||
TD_INTERFACE_IS_TYPE = 18,
|
||||
TD_LEGACY_ARRAY = 19,
|
||||
TD_PSTRING_SIZE_IS = 20,
|
||||
TD_PWSTRING_SIZE_IS = 21,
|
||||
TD_DOMOBJECT = 22,
|
||||
TD_PROMISE = 23,
|
||||
_TD_LAST_POINTER = TD_PROMISE,
|
||||
|
||||
// Complex Types
|
||||
// - Require cleanup,
|
||||
// - Always passed indirectly,
|
||||
// - Outparams must be initialized by caller,
|
||||
// - Supported in xptcall due to indirection.
|
||||
TD_DOMSTRING = 24,
|
||||
TD_UTF8STRING = 25,
|
||||
TD_CSTRING = 26,
|
||||
TD_ASTRING = 27,
|
||||
TD_JSVAL = 28,
|
||||
TD_ARRAY = 29,
|
||||
_TD_LAST_COMPLEX = TD_ARRAY
|
||||
TD_DOMSTRING = 15,
|
||||
TD_PSTRING = 16,
|
||||
TD_PWSTRING = 17,
|
||||
TD_INTERFACE_TYPE = 18,
|
||||
TD_INTERFACE_IS_TYPE = 19,
|
||||
TD_ARRAY = 20,
|
||||
TD_PSTRING_SIZE_IS = 21,
|
||||
TD_PWSTRING_SIZE_IS = 22,
|
||||
TD_UTF8STRING = 23,
|
||||
TD_CSTRING = 24,
|
||||
TD_ASTRING = 25,
|
||||
TD_JSVAL = 26,
|
||||
TD_DOMOBJECT = 27,
|
||||
TD_PROMISE = 28
|
||||
};
|
||||
|
||||
static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
|
||||
|
||||
|
||||
/*
|
||||
* A nsXPTType is a union used to identify the type of a method argument or
|
||||
|
@ -220,34 +193,27 @@ static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
|
|||
*/
|
||||
struct nsXPTType
|
||||
{
|
||||
nsXPTTypeTag Tag() const { return static_cast<nsXPTTypeTag>(mTag); }
|
||||
// NOTE: This is uint8_t instead of nsXPTTypeTag so that it can be compared
|
||||
// with the nsXPTType::* re-exports.
|
||||
uint8_t Tag() const { return mTag; }
|
||||
|
||||
// The index in the function argument list which should be used when
|
||||
// determining the iid_is or size_is properties of this dependent type.
|
||||
uint8_t ArgNum() const {
|
||||
MOZ_ASSERT(Tag() == TD_INTERFACE_IS_TYPE ||
|
||||
Tag() == TD_PSTRING_SIZE_IS ||
|
||||
Tag() == TD_PWSTRING_SIZE_IS ||
|
||||
Tag() == TD_LEGACY_ARRAY);
|
||||
Tag() == TD_ARRAY);
|
||||
return mData1;
|
||||
}
|
||||
|
||||
const nsXPTType& ArrayElementType() const {
|
||||
MOZ_ASSERT(Tag() == TD_ARRAY);
|
||||
return xpt::detail::GetType(mData2);
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper for reading 16-bit data values split between mData1 and mData2.
|
||||
uint16_t Data16() const { return ((uint16_t)mData1 << 8) | mData2; }
|
||||
|
||||
public:
|
||||
// Get the type of the element in the current array or sequence. Arrays only
|
||||
// fit 8 bits of type data, while sequences support up to 16 bits of type data
|
||||
// due to not needing to store an ArgNum.
|
||||
const nsXPTType& ArrayElementType() const {
|
||||
if (Tag() == TD_LEGACY_ARRAY) {
|
||||
return xpt::detail::GetType(mData2);
|
||||
}
|
||||
MOZ_ASSERT(Tag() == TD_ARRAY);
|
||||
return xpt::detail::GetType(Data16());
|
||||
}
|
||||
|
||||
// We store the 16-bit iface value as two 8-bit values in order to
|
||||
// avoid 16-bit alignment requirements for XPTTypeDescriptor, which
|
||||
// reduces its size and also the size of XPTParamDescriptor.
|
||||
|
@ -261,44 +227,43 @@ public:
|
|||
return xpt::detail::GetDOMObjectInfo(Data16());
|
||||
}
|
||||
|
||||
// See the comments in nsXPTTypeTag for an explanation as to what each of
|
||||
// these categories mean.
|
||||
bool IsArithmetic() const { return Tag() <= _TD_LAST_ARITHMETIC; }
|
||||
bool IsPointer() const { return !IsArithmetic() && Tag() <= _TD_LAST_POINTER; }
|
||||
bool IsComplex() const { return Tag() > _TD_LAST_POINTER; }
|
||||
// 'Arithmetic' here roughly means that the value is self-contained and
|
||||
// doesn't depend on anything else in memory (ie: not a pointer, not an
|
||||
// XPCOM object, not a jsval, etc).
|
||||
//
|
||||
// Supposedly this terminology comes from Harbison/Steele, but it's still
|
||||
// a rather crappy name. We'd change it if it wasn't used all over the
|
||||
// place in xptcall. :-(
|
||||
bool IsArithmetic() const { return Tag() <= TD_WCHAR; }
|
||||
|
||||
bool IsInterfacePointer() const {
|
||||
return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
|
||||
}
|
||||
|
||||
bool IsArray() const { return Tag() == TD_ARRAY; }
|
||||
|
||||
bool IsDependent() const {
|
||||
return (Tag() == TD_ARRAY && InnermostType().IsDependent()) ||
|
||||
Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_LEGACY_ARRAY ||
|
||||
return Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_ARRAY ||
|
||||
Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
|
||||
}
|
||||
|
||||
// Unwrap a nested type to its innermost value (e.g. through arrays).
|
||||
const nsXPTType& InnermostType() const {
|
||||
if (Tag() == TD_LEGACY_ARRAY || Tag() == TD_ARRAY) {
|
||||
if (Tag() == TD_ARRAY) {
|
||||
return ArrayElementType().InnermostType();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// In-memory size of native type in bytes.
|
||||
// Helper methods for working with the type's native representation.
|
||||
inline size_t Stride() const;
|
||||
inline bool HasPointerRepr() const;
|
||||
|
||||
// Offset the given base pointer to reference the element at the given index.
|
||||
void* ElementPtr(const void* aBase, uint32_t aIndex) const {
|
||||
return (char*)aBase + (aIndex * Stride());
|
||||
}
|
||||
|
||||
// Zero out a native value of the given type. The type must not be 'complex'.
|
||||
void ZeroValue(void* aValue) const {
|
||||
MOZ_RELEASE_ASSERT(!IsComplex(), "Cannot zero a complex value");
|
||||
memset(aValue, 0, Stride());
|
||||
}
|
||||
|
||||
// Indexes into the extra types array of a small set of known types.
|
||||
enum class Idx : uint8_t
|
||||
{
|
||||
|
@ -324,7 +289,7 @@ public:
|
|||
// Helper methods for fabricating nsXPTType values used by xpconnect.
|
||||
static nsXPTType MkArrayType(Idx aInner) {
|
||||
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
|
||||
return { TD_LEGACY_ARRAY, false, false, false, 0, (uint8_t)aInner };
|
||||
return { TD_ARRAY, false, false, false, 0, (uint8_t)aInner };
|
||||
}
|
||||
static const nsXPTType& Get(Idx aInner) {
|
||||
MOZ_ASSERT(aInner <= Idx::INTERFACE_IS_TYPE);
|
||||
|
@ -335,41 +300,42 @@ public:
|
|||
// nsXPTType backwards compatibility //
|
||||
///////////////////////////////////////
|
||||
|
||||
nsXPTType& operator=(nsXPTTypeTag aPrefix) { mTag = aPrefix; return *this; }
|
||||
operator nsXPTTypeTag() const { return Tag(); }
|
||||
nsXPTType& operator=(uint8_t aPrefix) { mTag = aPrefix; return *this; }
|
||||
operator uint8_t() const { return TagPart(); };
|
||||
uint8_t TagPart() const { return mTag; };
|
||||
|
||||
#define TD_ALIAS_(name_, value_) static constexpr nsXPTTypeTag name_ = value_
|
||||
TD_ALIAS_(T_I8 , TD_INT8 );
|
||||
TD_ALIAS_(T_I16 , TD_INT16 );
|
||||
TD_ALIAS_(T_I32 , TD_INT32 );
|
||||
TD_ALIAS_(T_I64 , TD_INT64 );
|
||||
TD_ALIAS_(T_U8 , TD_UINT8 );
|
||||
TD_ALIAS_(T_U16 , TD_UINT16 );
|
||||
TD_ALIAS_(T_U32 , TD_UINT32 );
|
||||
TD_ALIAS_(T_U64 , TD_UINT64 );
|
||||
TD_ALIAS_(T_FLOAT , TD_FLOAT );
|
||||
TD_ALIAS_(T_DOUBLE , TD_DOUBLE );
|
||||
TD_ALIAS_(T_BOOL , TD_BOOL );
|
||||
TD_ALIAS_(T_CHAR , TD_CHAR );
|
||||
TD_ALIAS_(T_WCHAR , TD_WCHAR );
|
||||
TD_ALIAS_(T_VOID , TD_VOID );
|
||||
TD_ALIAS_(T_IID , TD_PNSIID );
|
||||
TD_ALIAS_(T_DOMSTRING , TD_DOMSTRING );
|
||||
TD_ALIAS_(T_CHAR_STR , TD_PSTRING );
|
||||
TD_ALIAS_(T_WCHAR_STR , TD_PWSTRING );
|
||||
TD_ALIAS_(T_INTERFACE , TD_INTERFACE_TYPE );
|
||||
TD_ALIAS_(T_INTERFACE_IS , TD_INTERFACE_IS_TYPE);
|
||||
TD_ALIAS_(T_LEGACY_ARRAY , TD_LEGACY_ARRAY );
|
||||
TD_ALIAS_(T_PSTRING_SIZE_IS , TD_PSTRING_SIZE_IS );
|
||||
TD_ALIAS_(T_PWSTRING_SIZE_IS , TD_PWSTRING_SIZE_IS );
|
||||
TD_ALIAS_(T_UTF8STRING , TD_UTF8STRING );
|
||||
TD_ALIAS_(T_CSTRING , TD_CSTRING );
|
||||
TD_ALIAS_(T_ASTRING , TD_ASTRING );
|
||||
TD_ALIAS_(T_JSVAL , TD_JSVAL );
|
||||
TD_ALIAS_(T_DOMOBJECT , TD_DOMOBJECT );
|
||||
TD_ALIAS_(T_PROMISE , TD_PROMISE );
|
||||
TD_ALIAS_(T_ARRAY , TD_ARRAY );
|
||||
#undef TD_ALIAS_
|
||||
enum // Re-export TD_ interfaces from nsXPTType
|
||||
{
|
||||
T_I8 = TD_INT8 ,
|
||||
T_I16 = TD_INT16 ,
|
||||
T_I32 = TD_INT32 ,
|
||||
T_I64 = TD_INT64 ,
|
||||
T_U8 = TD_UINT8 ,
|
||||
T_U16 = TD_UINT16 ,
|
||||
T_U32 = TD_UINT32 ,
|
||||
T_U64 = TD_UINT64 ,
|
||||
T_FLOAT = TD_FLOAT ,
|
||||
T_DOUBLE = TD_DOUBLE ,
|
||||
T_BOOL = TD_BOOL ,
|
||||
T_CHAR = TD_CHAR ,
|
||||
T_WCHAR = TD_WCHAR ,
|
||||
T_VOID = TD_VOID ,
|
||||
T_IID = TD_PNSIID ,
|
||||
T_DOMSTRING = TD_DOMSTRING ,
|
||||
T_CHAR_STR = TD_PSTRING ,
|
||||
T_WCHAR_STR = TD_PWSTRING ,
|
||||
T_INTERFACE = TD_INTERFACE_TYPE ,
|
||||
T_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
|
||||
T_ARRAY = TD_ARRAY ,
|
||||
T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
|
||||
T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
|
||||
T_UTF8STRING = TD_UTF8STRING ,
|
||||
T_CSTRING = TD_CSTRING ,
|
||||
T_ASTRING = TD_ASTRING ,
|
||||
T_JSVAL = TD_JSVAL ,
|
||||
T_DOMOBJECT = TD_DOMOBJECT ,
|
||||
T_PROMISE = TD_PROMISE
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Ensure these fields are in the same order as xptcodegen.py //
|
||||
|
@ -410,10 +376,15 @@ struct nsXPTParamInfo
|
|||
const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
|
||||
|
||||
// Whether this parameter is passed indirectly on the stack. All out/inout
|
||||
// params are passed indirectly, and complex types are always passed
|
||||
// indirectly.
|
||||
// params are passed indirectly, although some types are passed indirectly
|
||||
// unconditionally.
|
||||
bool IsIndirect() const {
|
||||
return IsOut() || Type().IsComplex();
|
||||
return IsOut() ||
|
||||
mType.Tag() == TD_JSVAL ||
|
||||
mType.Tag() == TD_ASTRING ||
|
||||
mType.Tag() == TD_DOMSTRING ||
|
||||
mType.Tag() == TD_CSTRING ||
|
||||
mType.Tag() == TD_UTF8STRING;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
@ -531,34 +502,6 @@ struct nsXPTDOMObjectInfo
|
|||
namespace xpt {
|
||||
namespace detail {
|
||||
|
||||
// The UntypedTArray type allows low-level access from XPConnect to nsTArray
|
||||
// internals without static knowledge of the array element type in question.
|
||||
class UntypedTArray
|
||||
: public nsTArray_base<nsTArrayFallibleAllocator, nsTArray_CopyWithMemutils>
|
||||
{
|
||||
public:
|
||||
void* Elements() const {
|
||||
return static_cast<void*>(Hdr() + 1);
|
||||
}
|
||||
|
||||
// Changes the length and capacity to be at least large enough for aTo elements.
|
||||
bool SetLength(const nsXPTType& aEltTy, uint32_t aTo) {
|
||||
if (!EnsureCapacity<nsTArrayFallibleAllocator>(aTo, aEltTy.Stride())) {
|
||||
return false;
|
||||
}
|
||||
mHdr->mLength = aTo;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Free backing memory for the nsTArray object.
|
||||
void Clear() {
|
||||
if (mHdr != EmptyHdr() && !UsesAutoArrayBuffer()) {
|
||||
nsTArrayFallibleAllocator::Free(mHdr);
|
||||
}
|
||||
mHdr = EmptyHdr();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The compressed representation of constants from XPT. Not part of the public
|
||||
* interface, as we also need to support Shim interfaces.
|
||||
|
@ -650,11 +593,39 @@ GetString(uint32_t aIndex)
|
|||
} // namespace detail
|
||||
} // namespace xpt
|
||||
|
||||
inline bool
|
||||
nsXPTType::HasPointerRepr() const
|
||||
{
|
||||
// This method should return `true` if the given type would be represented as
|
||||
// a pointer when not passed indirectly.
|
||||
switch (Tag()) {
|
||||
case TD_VOID:
|
||||
case TD_PNSIID:
|
||||
case TD_PSTRING:
|
||||
case TD_PWSTRING:
|
||||
case TD_INTERFACE_TYPE:
|
||||
case TD_INTERFACE_IS_TYPE:
|
||||
case TD_ARRAY:
|
||||
case TD_PSTRING_SIZE_IS:
|
||||
case TD_PWSTRING_SIZE_IS:
|
||||
case TD_DOMOBJECT:
|
||||
case TD_PROMISE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t
|
||||
nsXPTType::Stride() const
|
||||
{
|
||||
// Compute the stride to use when walking an array of the given type.
|
||||
switch (Tag()) {
|
||||
//
|
||||
// NOTE: We cast to nsXPTTypeTag here so we get a warning if a type is missed
|
||||
// in this switch statement. It's important that this method returns a value
|
||||
// for every possible type.
|
||||
|
||||
switch (static_cast<nsXPTTypeTag>(Tag())) {
|
||||
case TD_INT8: return sizeof(int8_t);
|
||||
case TD_INT16: return sizeof(int16_t);
|
||||
case TD_INT32: return sizeof(int32_t);
|
||||
|
@ -668,7 +639,6 @@ nsXPTType::Stride() const
|
|||
case TD_BOOL: return sizeof(bool);
|
||||
case TD_CHAR: return sizeof(char);
|
||||
case TD_WCHAR: return sizeof(char16_t);
|
||||
|
||||
case TD_VOID: return sizeof(void*);
|
||||
case TD_PNSIID: return sizeof(nsIID*);
|
||||
case TD_DOMSTRING: return sizeof(nsString);
|
||||
|
@ -676,17 +646,15 @@ nsXPTType::Stride() const
|
|||
case TD_PWSTRING: return sizeof(char16_t*);
|
||||
case TD_INTERFACE_TYPE: return sizeof(nsISupports*);
|
||||
case TD_INTERFACE_IS_TYPE: return sizeof(nsISupports*);
|
||||
case TD_LEGACY_ARRAY: return sizeof(void*);
|
||||
case TD_ARRAY: return sizeof(void*);
|
||||
case TD_PSTRING_SIZE_IS: return sizeof(char*);
|
||||
case TD_PWSTRING_SIZE_IS: return sizeof(char16_t*);
|
||||
case TD_DOMOBJECT: return sizeof(void*);
|
||||
case TD_PROMISE: return sizeof(void*);
|
||||
|
||||
case TD_UTF8STRING: return sizeof(nsCString);
|
||||
case TD_CSTRING: return sizeof(nsCString);
|
||||
case TD_ASTRING: return sizeof(nsString);
|
||||
case TD_JSVAL: return sizeof(JS::Value);
|
||||
case TD_ARRAY: return sizeof(xpt::detail::UntypedTArray);
|
||||
case TD_DOMOBJECT: return sizeof(void*);
|
||||
case TD_PROMISE: return sizeof(void*);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unknown type");
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// re-export libc so it can be used by the procedural macro.
|
||||
pub extern crate libc;
|
||||
|
||||
pub use nsstring::{nsACString, nsAString, nsCString, nsString};
|
||||
pub use nsstring::{nsACString, nsAString};
|
||||
|
||||
pub use nserror::{nsresult, NsresultExt, NS_ERROR_NO_INTERFACE, NS_OK};
|
||||
|
||||
|
|
|
@ -563,9 +563,7 @@ fn xpcom(init: DeriveInput) -> Result<Tokens, Box<Error>> {
|
|||
#[allow(unused_imports)]
|
||||
use ::xpcom::interfaces::*;
|
||||
#[allow(unused_imports)]
|
||||
use ::xpcom::reexports::{
|
||||
libc, nsACString, nsAString, nsCString, nsString, nsresult
|
||||
};
|
||||
use ::xpcom::reexports::{libc, nsACString, nsAString, nsresult};
|
||||
|
||||
unsafe {
|
||||
// NOTE: This is split into multiple lines to make the
|
||||
|
|
|
@ -382,25 +382,6 @@ TEST(TArray, test_move_array) {
|
|||
differentAllocatorMoveableArray2 = std::move(autoMoveableArray2);
|
||||
|
||||
ASSERT_EQ(Moveable::Count(), 8);
|
||||
|
||||
AutoTArray<Moveable, 8> moveableAutoArray;
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
ASSERT_TRUE(moveableAutoArray.AppendElement(Moveable()));
|
||||
}
|
||||
|
||||
ASSERT_EQ(Moveable::Count(), 12);
|
||||
|
||||
const AutoTArray<Moveable, 8>& constRefMoveableAutoArray = moveableAutoArray;
|
||||
|
||||
ASSERT_EQ(Moveable::Count(), 12);
|
||||
|
||||
AutoTArray<Moveable, 8> copyMoveableAutoArray(constRefMoveableAutoArray);
|
||||
|
||||
ASSERT_EQ(Moveable::Count(), 16);
|
||||
|
||||
AutoTArray<Moveable, 8> movedMoveableAutoArray(std::move(moveableAutoArray));
|
||||
|
||||
ASSERT_EQ(Moveable::Count(), 16);
|
||||
}
|
||||
|
||||
//----
|
||||
|
|
Загрузка…
Ссылка в новой задаче