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 (bug 1474369)
Backed out changeset a8a4e2414daa (bug 1474369)
Backed out changeset 13c9626970e2 (bug 1474369)
Backed out changeset 9817819b7765 (bug 1475409)
Backed out changeset 39fcebfe6529 (bug 1475409)
Backed out changeset c19ca740d3d1 (bug 1475409)
Backed out changeset b26c90518fca (bug 1474369)
Backed out changeset cbdde0474521 (bug 1474369)
Backed out changeset ccea3049fe0f (bug 1474369)
Backed out changeset e9f6d2544a82 (bug 1474369)
Backed out changeset 99c4d07d4b88 (bug 1474369)
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:
Cosmin Sabou 2018-07-30 20:31:24 +03:00
Родитель a78b7458a9
Коммит e748fd8968
24 изменённых файлов: 569 добавлений и 892 удалений

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

@ -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(&current, type.ElementPtr(buf, i), type, iid, 0, pErr) ||
if (!NativeData2JS(&current, 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, &current) ||
!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, &current) ||
!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);
}
//----