mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 699156: Support TypedArrays in XPConnect. r=bholley,evilpie
This commit is contained in:
parent
92f0b64ffe
commit
55185ebf5e
@ -58,6 +58,8 @@
|
||||
#include "dombindings.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
#include "jstypedarray.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//#define STRICT_CHECK_OF_UNICODE
|
||||
@ -1689,13 +1691,169 @@ failure:
|
||||
#undef POPULATE
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check that the tag part of the type matches the type
|
||||
// of the array. If the check succeeds, check that the size
|
||||
// of the output does not exceed PR_UINT32_MAX bytes. Allocate
|
||||
// the memory and copy the elements by memcpy.
|
||||
static JSBool
|
||||
CheckTargetAndPopulate(const nsXPTType& type,
|
||||
PRUint8 requiredType,
|
||||
size_t typeSize,
|
||||
JSUint32 count,
|
||||
JSObject* tArr,
|
||||
void** output,
|
||||
nsresult* pErr)
|
||||
{
|
||||
// Check that the element type expected by the interface matches
|
||||
// the type of the elements in the typed array exactly, including
|
||||
// signedness.
|
||||
if (type.TagPart() != requiredType) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calulate the maximum number of elements that can fit in
|
||||
// PR_UINT32_MAX bytes.
|
||||
size_t max = PR_UINT32_MAX / typeSize;
|
||||
|
||||
// This could overflow on 32-bit systems so check max first.
|
||||
size_t byteSize = count * typeSize;
|
||||
if (count > max || !(*output = nsMemory::Alloc(byteSize))) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*output, JS_GetTypedArrayData(tArr), byteSize);
|
||||
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.
|
||||
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::JSTypedArray2Native(XPCCallContext& ccx,
|
||||
void** d,
|
||||
JSObject* jsArray,
|
||||
JSUint32 count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(jsArray, "bad param");
|
||||
NS_ABORT_IF_FALSE(d, "bad param");
|
||||
NS_ABORT_IF_FALSE(js_IsTypedArray(jsArray), "not a typed array");
|
||||
|
||||
// Check the actual length of the input array against the
|
||||
// given size_is.
|
||||
JSUint32 len = JS_GetTypedArrayLength(jsArray);
|
||||
if (len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* output = nsnull;
|
||||
|
||||
switch (JS_GetTypedArrayType(jsArray)) {
|
||||
case js::TypedArray::TYPE_INT8:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_I8, type,
|
||||
sizeof(int8), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_UINT8:
|
||||
case js::TypedArray::TYPE_UINT8_CLAMPED:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_U8, type,
|
||||
sizeof(uint8), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_INT16:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_I16, type,
|
||||
sizeof(int16), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_UINT16:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_U16, type,
|
||||
sizeof(uint16), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_INT32:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_I32, type,
|
||||
sizeof(int32), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_UINT32:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_U32, type,
|
||||
sizeof(uint32), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_FLOAT32:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_FLOAT, type,
|
||||
sizeof(float), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case js::TypedArray::TYPE_FLOAT64:
|
||||
if (!CheckTargetAndPopulate(nsXPTType::T_DOUBLE, type,
|
||||
sizeof(double), count,
|
||||
jsArray, &output, pErr)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// Yet another array type was defined? It is not supported yet...
|
||||
default:
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
*d = output;
|
||||
if (pErr)
|
||||
*pErr = NS_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
JSBool
|
||||
XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
|
||||
JSUint32 count, const nsXPTType& type,
|
||||
const nsID* iid, uintN* pErr)
|
||||
const nsID* iid, nsresult* pErr)
|
||||
{
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
NS_ABORT_IF_FALSE(d, "bad param");
|
||||
|
||||
JSContext* cx = ccx.GetJSContext();
|
||||
|
||||
@ -1731,13 +1889,19 @@ XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
|
||||
}
|
||||
|
||||
jsarray = JSVAL_TO_OBJECT(s);
|
||||
|
||||
// If this is a typed array, then do a fast conversion with memcpy.
|
||||
if (js_IsTypedArray(jsarray)) {
|
||||
return JSTypedArray2Native(ccx, d, jsarray, count, type, pErr);
|
||||
}
|
||||
|
||||
if (!JS_IsArrayObject(cx, jsarray)) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
jsuint len;
|
||||
JSUint32 len;
|
||||
if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) {
|
||||
if (pErr)
|
||||
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
|
||||
@ -1781,7 +1945,7 @@ XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
|
||||
case nsXPTType::T_U64 : POPULATE(na, uint64); break;
|
||||
case nsXPTType::T_FLOAT : POPULATE(na, float); break;
|
||||
case nsXPTType::T_DOUBLE : POPULATE(na, double); break;
|
||||
case nsXPTType::T_BOOL : POPULATE(na, bool); break;
|
||||
case nsXPTType::T_BOOL : POPULATE(na, bool); break;
|
||||
case nsXPTType::T_CHAR : POPULATE(na, char); break;
|
||||
case nsXPTType::T_WCHAR : POPULATE(na, jschar); break;
|
||||
case nsXPTType::T_VOID : NS_ERROR("bad type"); goto failure;
|
||||
@ -1874,7 +2038,7 @@ XPCConvert::NativeStringWithSize2JS(JSContext* cx,
|
||||
JSBool
|
||||
XPCConvert::JSStringWithSize2Native(XPCCallContext& ccx, void* d, jsval s,
|
||||
JSUint32 count, const nsXPTType& type,
|
||||
uintN* pErr)
|
||||
nsresult* pErr)
|
||||
{
|
||||
NS_PRECONDITION(!JSVAL_IS_NULL(s), "bad param");
|
||||
NS_PRECONDITION(d, "bad param");
|
||||
|
@ -2434,8 +2434,7 @@ CallMethodHelper::GatherAndConvertResults()
|
||||
!GetInterfaceTypeFromParam(i, datum_type, ¶m_iid))
|
||||
return false;
|
||||
|
||||
uintN err;
|
||||
|
||||
nsresult err;
|
||||
if (isArray) {
|
||||
XPCLazyCallContext lccx(mCallContext);
|
||||
if (!XPCConvert::NativeArray2JS(lccx, &v, (const void**)&dp->val,
|
||||
|
@ -3327,7 +3327,14 @@ public:
|
||||
|
||||
static JSBool JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
|
||||
JSUint32 count, const nsXPTType& type,
|
||||
const nsID* iid, uintN* pErr);
|
||||
const nsID* iid, nsresult* pErr);
|
||||
|
||||
static JSBool JSTypedArray2Native(XPCCallContext& ccx,
|
||||
void** d,
|
||||
JSObject* jsarray,
|
||||
JSUint32 count,
|
||||
const nsXPTType& type,
|
||||
nsresult* pErr);
|
||||
|
||||
static JSBool NativeStringWithSize2JS(JSContext* cx,
|
||||
jsval* d, const void* s,
|
||||
|
@ -97,7 +97,7 @@ TestParams.prototype = {
|
||||
testACString: f,
|
||||
testJsval: f,
|
||||
testShortArray: f_is,
|
||||
testLongLongArray: f_is,
|
||||
testDoubleArray: f_is,
|
||||
testStringArray: f_is,
|
||||
testWstringArray: f_is,
|
||||
testInterfaceArray: f_is,
|
||||
|
@ -246,14 +246,14 @@ NS_IMETHODIMP nsXPCTestParams::TestShortArray(PRUint32 aLength, PRInt16 *a,
|
||||
BUFFER_METHOD_IMPL(PRInt16, 0, TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
/* void testLongLongArray (in unsigned long aLength, [array, size_is (aLength)] in long long a,
|
||||
* inout unsigned long bLength, [array, size_is (bLength)] inout long long b,
|
||||
* out unsigned long rvLength, [array, size_is (rvLength), retval] out long long rv); */
|
||||
NS_IMETHODIMP nsXPCTestParams::TestLongLongArray(PRUint32 aLength, PRInt64 *a,
|
||||
PRUint32 *bLength NS_INOUTPARAM, PRInt64 **b NS_INOUTPARAM,
|
||||
PRUint32 *rvLength NS_OUTPARAM, PRInt64 **rv NS_OUTPARAM)
|
||||
/* void testDoubleArray (in unsigned long aLength, [array, size_is (aLength)] in double a,
|
||||
* inout unsigned long bLength, [array, size_is (bLength)] inout double b,
|
||||
* out unsigned long rvLength, [array, size_is (rvLength), retval] out double rv); */
|
||||
NS_IMETHODIMP nsXPCTestParams::TestDoubleArray(PRUint32 aLength, double *a,
|
||||
PRUint32 *bLength NS_INOUTPARAM, double **b NS_INOUTPARAM,
|
||||
PRUint32 *rvLength NS_OUTPARAM, double **rv NS_OUTPARAM)
|
||||
{
|
||||
BUFFER_METHOD_IMPL(PRInt64, 0, TAKE_OWNERSHIP_NOOP);
|
||||
BUFFER_METHOD_IMPL(double, 0, TAKE_OWNERSHIP_NOOP);
|
||||
}
|
||||
|
||||
/* void testStringArray (in unsigned long aLength, [array, size_is (aLength)] in string a,
|
||||
|
@ -47,7 +47,7 @@
|
||||
interface nsIXPCTestInterfaceA;
|
||||
interface nsIXPCTestInterfaceB;
|
||||
|
||||
[scriptable, uuid(b94cd289-d0df-4d25-8995-facf687d921d)]
|
||||
[scriptable, uuid(fe2b7433-ac3b-49ef-9344-b67228bfdd46)]
|
||||
interface nsIXPCTestParams : nsISupports {
|
||||
|
||||
// These types correspond to the ones in typelib.py
|
||||
@ -79,9 +79,9 @@ interface nsIXPCTestParams : nsISupports {
|
||||
void testShortArray(in unsigned long aLength, [array, size_is(aLength)] in short a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout short b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out short rv);
|
||||
void testLongLongArray(in unsigned long aLength, [array, size_is(aLength)] in long long a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout long long b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out long long rv);
|
||||
void testDoubleArray(in unsigned long aLength, [array, size_is(aLength)] in double a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout double b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out double rv);
|
||||
void testStringArray(in unsigned long aLength, [array, size_is(aLength)] in string a,
|
||||
inout unsigned long bLength, [array, size_is(bLength)] inout string b,
|
||||
out unsigned long rvLength, [retval, array, size_is(rvLength)] out string rv);
|
||||
|
@ -119,6 +119,22 @@ function test_component(contractid) {
|
||||
do_check_true(dotEqualsComparator(val1IID, bIID.value));
|
||||
}
|
||||
|
||||
// Check that the given call (type mismatch) results in an exception being thrown.
|
||||
function doTypedArrayMismatchTest(name, val1, val1Size, val2, val2Size) {
|
||||
var comparator = arrayComparator(standardComparator);
|
||||
var error = false;
|
||||
try {
|
||||
doIsTest(name, val1, val1Size, val2, val2Size, comparator);
|
||||
|
||||
// An exception was not thrown as would have been expected.
|
||||
do_check_true(false);
|
||||
}
|
||||
catch (e) {
|
||||
// An exception was thrown as expected.
|
||||
do_check_true(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for bug 687612 (inout parameters broken for dipper types).
|
||||
// We do a simple test of copying a into b, and ignore the rv.
|
||||
function doTestWorkaround(name, val1) {
|
||||
@ -165,7 +181,8 @@ function test_component(contractid) {
|
||||
|
||||
// Test arrays.
|
||||
doIsTest("testShortArray", [2, 4, 6], 3, [1, 3, 5, 7], 4, arrayComparator(standardComparator));
|
||||
doIsTest("testLongLongArray", [-10000000000], 1, [1, 3, 1234511234551], 3, arrayComparator(standardComparator));
|
||||
doIsTest("testDoubleArray", [-10, -0.5], 2, [1, 3, 1e11, -8e-5 ], 4, arrayComparator(fuzzComparator));
|
||||
|
||||
doIsTest("testStringArray", ["mary", "hat", "hey", "lid", "tell", "lam"], 6,
|
||||
["ids", "fleas", "woes", "wide", "has", "know", "!"], 7, arrayComparator(standardComparator));
|
||||
doIsTest("testWstringArray", ["沒有語言", "的偉大嗎?]"], 2,
|
||||
@ -173,6 +190,13 @@ function test_component(contractid) {
|
||||
doIsTest("testInterfaceArray", [makeA(), makeA()], 2,
|
||||
[makeA(), makeA(), makeA(), makeA(), makeA(), makeA()], 6, arrayComparator(interfaceComparator));
|
||||
|
||||
// Test typed arrays and ArrayBuffer aliasing.
|
||||
var arrayBuffer = new ArrayBuffer(16);
|
||||
var int16Array = new Int16Array(arrayBuffer, 2, 3);
|
||||
int16Array.set([-32768, 0, 32767]);
|
||||
doIsTest("testShortArray", int16Array, 3, new Int16Array([1773, -32768, 32767, 7]), 4, arrayComparator(standardComparator));
|
||||
doIsTest("testDoubleArray", new Float64Array([-10, -0.5]), 2, new Float64Array([0, 3.2, 1.0e10, -8.33 ]), 4, arrayComparator(fuzzComparator));
|
||||
|
||||
// Test sized strings.
|
||||
var ssTests = ["Tis not possible, I muttered", "give me back my free hardcore!", "quoth the server:", "4〠4"];
|
||||
doIsTest("testSizedString", ssTests[0], ssTests[0].length, ssTests[1], ssTests[1].length, standardComparator);
|
||||
@ -186,4 +210,12 @@ function test_component(contractid) {
|
||||
// Test arrays of iids.
|
||||
doIs2Test("testInterfaceIsArray", [makeA(), makeA(), makeA(), makeA(), makeA()], 5, Ci['nsIXPCTestInterfaceA'],
|
||||
[makeB(), makeB(), makeB()], 3, Ci['nsIXPCTestInterfaceB']);
|
||||
|
||||
// Test incorrect (too big) array size parameter; this should throw NOT_ENOUGH_ELEMENTS.
|
||||
doTypedArrayMismatchTest("testShortArray", Int16Array([-3, 7, 4]), 4,
|
||||
Int16Array([1, -32, 6]), 3);
|
||||
|
||||
// Test type mismatch (int16 <-> uint16); this should throw BAD_CONVERT_JS.
|
||||
doTypedArrayMismatchTest("testShortArray", Uint16Array([0, 7, 4, 3]), 4,
|
||||
Uint16Array([1, 5, 6]), 3);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user