From 984fff647d66ea2a7977a21b0bf4159ae0cebab6 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Wed, 19 May 2010 14:25:20 -0700 Subject: [PATCH] Bug 565604 - Typed-array properties don't work when accessed from an object whose prototype is a typed array. r=vlad --HG-- extra : rebase_source : 6ac630f7a9d2cb04a9a996c2a675be41130ea2b1 --- content/base/src/nsContentUtils.cpp | 2 +- content/canvas/src/CustomQS_WebGL.h | 16 ++-- js/src/jstypedarray.cpp | 74 ++++++++++++++----- js/src/tests/js1_8_5/extensions/jstests.list | 1 + .../extensions/typedarray-prototype.js | 47 ++++++++++++ 5 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 js/src/tests/js1_8_5/extensions/typedarray-prototype.js diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index adc5a9568578..2421fdc6767f 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -5520,7 +5520,7 @@ CloneSimpleValues(JSContext* cx, return SetPropertyOnValueOrObject(cx, val, rval, robj, rid); } - NS_ASSERTION(JSVAL_IS_OBJECT(val), "Not an object!"); + NS_ASSERTION(!JSVAL_IS_PRIMITIVE(val), "Not an object!"); JSObject* obj = JSVAL_TO_OBJECT(val); // Dense arrays of primitives can be cloned quickly. diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index 4099242551fa..fb93e0fb83be 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -88,7 +88,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) if (!JS_ValueToECMAInt32(cx, argv[2], &usage)) return JS_FALSE; - if (JSVAL_IS_OBJECT(argv[1])) { + if (!JSVAL_IS_PRIMITIVE(argv[1])) { JSObject *arg2 = JSVAL_TO_OBJECT(argv[1]); if (js_IsArrayBuffer(arg2)) { wb = js::ArrayBuffer::fromJSObject(arg2); @@ -153,7 +153,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v if (!JS_ValueToECMAInt32(cx, argv[1], &offset)) return JS_FALSE; - if (!JSVAL_IS_OBJECT(argv[2])) { + if (JSVAL_IS_PRIMITIVE(argv[2])) { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2); return JS_FALSE; } @@ -255,7 +255,11 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) // then try to grab either a js::ArrayBuffer, js::TypedArray, or null arg9 = JSVAL_TO_OBJECT(argv[8]); - if (js_IsArrayBuffer(arg9)) { + if (arg9 == nsnull) { + rv = self->TexImage2D_buf(intargs[0], intargs[1], intargs[2], intargs[3], + intargs[4], intargs[5], intargs[6], intargs[7], + nsnull); + } else if (js_IsArrayBuffer(arg9)) { rv = self->TexImage2D_buf(intargs[0], intargs[1], intargs[2], intargs[3], intargs[4], intargs[5], intargs[6], intargs[7], js::ArrayBuffer::fromJSObject(arg9)); @@ -263,10 +267,6 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) rv = self->TexImage2D_array(intargs[0], intargs[1], intargs[2], intargs[3], intargs[4], intargs[5], intargs[6], intargs[7], js::TypedArray::fromJSObject(arg9)); - } else if (arg9 == nsnull) { - rv = self->TexImage2D_buf(intargs[0], intargs[1], intargs[2], intargs[3], - intargs[4], intargs[5], intargs[6], intargs[7], - nsnull); } else { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8); return JS_FALSE; @@ -347,7 +347,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v return JS_FALSE; } - if (!JSVAL_IS_OBJECT(argv[8])) { + if (JSVAL_IS_PRIMITIVE(argv[8])) { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8); return JS_FALSE; } diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index d9cf66e2bbcc..8cfbe30612d6 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -223,40 +223,70 @@ TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip) return false; } +typedef jsval (* TypedArrayPropertyGetter)(TypedArray *tarray); + +template +class TypedArrayGetter { + public: + static inline bool get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { + do { + if (js_IsTypedArray(obj)) { + TypedArray *tarray = TypedArray::fromJSObject(obj); + if (tarray) + *vp = Get(tarray); + return true; + } + } while ((obj = obj->getProto()) != NULL); + return true; + } +}; + +inline jsval +getBuffer(TypedArray *tarray) +{ + return OBJECT_TO_JSVAL(tarray->bufferJS); +} + JSBool TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - TypedArray *tarray = fromJSObject(obj); - if (tarray) - *vp = OBJECT_TO_JSVAL(tarray->bufferJS); - return true; + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline jsval +getByteOffset(TypedArray *tarray) +{ + return INT_TO_JSVAL(tarray->byteOffset); } JSBool TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - TypedArray *tarray = fromJSObject(obj); - if (tarray) - *vp = INT_TO_JSVAL(tarray->byteOffset); - return true; + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline jsval +getByteLength(TypedArray *tarray) +{ + return INT_TO_JSVAL(tarray->byteLength); } JSBool TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - TypedArray *tarray = fromJSObject(obj); - if (tarray) - *vp = INT_TO_JSVAL(tarray->byteLength); - return true; + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline jsval +getLength(TypedArray *tarray) +{ + return INT_TO_JSVAL(tarray->length); } JSBool TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - TypedArray *tarray = fromJSObject(obj); - if (tarray) - *vp = INT_TO_JSVAL(tarray->length); - return true; + return TypedArrayGetter::get(cx, obj, id, vp); } JSBool @@ -1404,15 +1434,17 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj) JS_FRIEND_API(JSBool) js_IsArrayBuffer(JSObject *obj) { - return obj && obj->getClass() == &ArrayBuffer::jsclass; + JS_ASSERT(obj); + return obj->getClass() == &ArrayBuffer::jsclass; } JS_FRIEND_API(JSBool) js_IsTypedArray(JSObject *obj) { - return obj && - obj->getClass() >= &TypedArray::fastClasses[0] && - obj->getClass() < &TypedArray::fastClasses[TypedArray::TYPE_MAX]; + JS_ASSERT(obj); + JSClass *clasp = obj->getClass(); + return clasp >= &TypedArray::fastClasses[0] && + clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX]; } JS_FRIEND_API(JSObject *) @@ -1536,6 +1568,8 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_FRIEND_API(JSBool) js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope) { + JS_ASSERT(obj); + scope = JS_GetGlobalForObject(cx, scope); if (!scope) return JS_FALSE; diff --git a/js/src/tests/js1_8_5/extensions/jstests.list b/js/src/tests/js1_8_5/extensions/jstests.list index a18048662452..43f721b0468a 100644 --- a/js/src/tests/js1_8_5/extensions/jstests.list +++ b/js/src/tests/js1_8_5/extensions/jstests.list @@ -1,5 +1,6 @@ url-prefix ../../jsreftest.html?test=js1_8_5/extensions/ script typedarray.js +script typedarray-prototype.js skip-if(!xulRuntime.shell) script worker-error.js # these tests sometimes hang in browser, bug 559954, bug 562333 skip-if(!xulRuntime.shell) script worker-error-propagation.js skip-if(!xulRuntime.shell) script worker-fib.js diff --git a/js/src/tests/js1_8_5/extensions/typedarray-prototype.js b/js/src/tests/js1_8_5/extensions/typedarray-prototype.js new file mode 100644 index 000000000000..1e9bccebdf18 --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/typedarray-prototype.js @@ -0,0 +1,47 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +var gTestfile = 'typedarray-prototype.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 565604; +var summary = + "Typed-array properties don't work when accessed from an object whose " + + "prototype (or further-descended prototype) is a typed array"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var o = Object.create(new Uint8Array(1)); +assertEq(o.length, 1); + +var o2 = Object.create(o); +assertEq(o2.length, 1); + +var VARIABLE_OBJECT = {}; + +var props = + [ + { property: "length", value: 1 }, + { property: "byteLength", value: 1 }, + { property: "byteOffset", value: 0 }, + { property: "buffer", value: VARIABLE_OBJECT }, + ]; +for (var i = 0, sz = props.length; i < sz; i++) +{ + var p = props[i]; + + var o = Object.create(new Uint8Array(1)); + var v = o[p.property]; + if (p.value !== VARIABLE_OBJECT) + assertEq(o[p.property], p.value, "bad " + p.property + " (proto)"); + + var o2 = Object.create(o); + if (p.value !== VARIABLE_OBJECT) + assertEq(o2[p.property], p.value, "bad " + p.property + " (grand-proto)"); + assertEq(o2[p.property], v, p.property + " mismatch"); +} + +reportCompare(true, true);