[tor-commits] [tor-browser/esr24] Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff, a=lmandel
mikeperry at torproject.org
mikeperry at torproject.org
Fri Aug 29 05:26:41 UTC 2014
commit 9aeffb05a552f1beb1ff37adc88df0640ffa8ca3
Author: Jeff Walden <jwalden at mit.edu>
Date: Mon Jun 2 11:25:43 2014 -0700
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff, a=lmandel
--HG--
extra : rebase_source : 2487b6e09f4caf827c3ba5e0283e3d30c74e5d42
---
CLOBBER | 2 +-
content/base/src/WebSocket.cpp | 10 +-
content/base/src/nsDOMDataChannel.cpp | 10 +-
content/base/src/nsDOMParser.cpp | 2 +
content/base/src/nsXMLHttpRequest.cpp | 11 +-
content/canvas/src/CanvasRenderingContext2D.cpp | 14 +-
content/canvas/src/CanvasRenderingContext2D.h | 3 +-
content/canvas/src/WebGLContext.h | 15 ++
content/canvas/src/WebGLContextGL.cpp | 43 ++++-
content/html/content/public/HTMLAudioElement.h | 1 +
content/media/webaudio/AnalyserNode.cpp | 6 +
content/media/webaudio/AudioContext.cpp | 17 +-
content/media/webaudio/AudioParam.h | 1 +
content/media/webaudio/BiquadFilterNode.cpp | 4 +
content/media/webaudio/WaveShaperNode.cpp | 2 +
dom/bindings/TypedArray.h | 88 +++++++----
dom/encoding/TextDecoder.h | 1 +
dom/workers/TextDecoder.h | 1 +
js/src/builtin/TestingFunctions.cpp | 50 ++++++
js/src/jit/IonBuilder.cpp | 92 +----------
js/src/jit/MIR.h | 10 +-
js/src/js.msg | 4 +-
js/src/jsfriendapi.h | 111 +++++++++++++
js/src/jstypedarray.cpp | 190 +++++++++++++++++------
js/src/jstypedarray.h | 16 +-
js/src/jstypedarrayinlines.h | 8 +
netwerk/base/src/ArrayBufferInputStream.cpp | 11 ++
xpcom/io/nsBinaryStream.cpp | 56 +++++--
28 files changed, 561 insertions(+), 218 deletions(-)
diff --git a/CLOBBER b/CLOBBER
index 469d72c..550e8c1 100644
--- a/CLOBBER
+++ b/CLOBBER
@@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
-Bug 902908 renamed js/src/ion to js/src/jit and required a clobber
\ No newline at end of file
+Bug 999651 et al. require a clobber for some unknown reason
diff --git a/content/base/src/WebSocket.cpp b/content/base/src/WebSocket.cpp
index aba7007..2953aa3 100644
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -1221,7 +1221,10 @@ WebSocket::Send(ArrayBuffer& aData,
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
- MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+ aData.ComputeLengthAndData();
+
+ static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
uint32_t len = aData.Length();
char* data = reinterpret_cast<char*>(aData.Data());
@@ -1235,7 +1238,10 @@ WebSocket::Send(ArrayBufferView& aData,
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
- MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+ aData.ComputeLengthAndData();
+
+ static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
uint32_t len = aData.Length();
char* data = reinterpret_cast<char*>(aData.Data());
diff --git a/content/base/src/nsDOMDataChannel.cpp b/content/base/src/nsDOMDataChannel.cpp
index 3e038de..a7f4d93 100644
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -292,7 +292,10 @@ nsDOMDataChannel::Send(ArrayBuffer& aData, ErrorResult& aRv)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
- MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+ aData.ComputeLengthAndData();
+
+ static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
uint32_t len = aData.Length();
char* data = reinterpret_cast<char*>(aData.Data());
@@ -305,7 +308,10 @@ nsDOMDataChannel::Send(ArrayBufferView& aData, ErrorResult& aRv)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
- MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+ aData.ComputeLengthAndData();
+
+ static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
uint32_t len = aData.Length();
char* data = reinterpret_cast<char*>(aData.Data());
diff --git a/content/base/src/nsDOMParser.cpp b/content/base/src/nsDOMParser.cpp
index 0ab06d9..c6bc60d 100644
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -137,6 +137,8 @@ already_AddRefed<nsIDocument>
nsDOMParser::ParseFromBuffer(const Uint8Array& aBuf, uint32_t aBufLen,
SupportedType aType, ErrorResult& rv)
{
+ aBuf.ComputeLengthAndData();
+
if (aBufLen > aBuf.Length()) {
rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
return nullptr;
diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp
index 22fe0c8..418edae 100644
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2440,6 +2440,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLe
JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(realVal));
if (JS_IsArrayBufferObject(obj)) {
ArrayBuffer buf(obj);
+ buf.ComputeLengthAndData();
return GetRequestBody(buf.Data(), buf.Length(), aResult,
aContentLength, aContentType, aCharset);
}
@@ -2483,14 +2484,16 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
switch (body.GetType()) {
case nsXMLHttpRequest::RequestBody::ArrayBuffer:
{
- return ::GetRequestBody(value.mArrayBuffer->Data(),
- value.mArrayBuffer->Length(), aResult,
+ const ArrayBuffer* buffer = value.mArrayBuffer;
+ buffer->ComputeLengthAndData();
+ return ::GetRequestBody(buffer->Data(), buffer->Length(), aResult,
aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::ArrayBufferView:
{
- return ::GetRequestBody(value.mArrayBufferView->Data(),
- value.mArrayBufferView->Length(), aResult,
+ const ArrayBufferView* view = value.mArrayBufferView;
+ view->ComputeLengthAndData();
+ return ::GetRequestBody(view->Data(), view->Length(), aResult,
aContentLength, aContentType, aCharset);
}
case nsXMLHttpRequest::RequestBody::Blob:
diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp
index 8c67a87..ea685f1 100644
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -3559,7 +3559,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
imageData.Width(), imageData.Height(),
- arr.Data(), arr.Length(), false, 0, 0, 0, 0);
+ &arr, false, 0, 0, 0, 0);
}
void
@@ -3573,7 +3573,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
imageData.Width(), imageData.Height(),
- arr.Data(), arr.Length(), true,
+ &arr, true,
JS_DoubleToInt32(dirtyX),
JS_DoubleToInt32(dirtyY),
JS_DoubleToInt32(dirtyWidth),
@@ -3585,7 +3585,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
nsresult
CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
- unsigned char *aData, uint32_t aDataLen,
+ dom::Uint8ClampedArray* aArray,
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
int32_t dirtyWidth, int32_t dirtyHeight)
{
@@ -3638,8 +3638,12 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
return NS_OK;
}
+ aArray->ComputeLengthAndData();
+
+ uint32_t dataLen = aArray->Length();
+
uint32_t len = w * h * 4;
- if (aDataLen != len) {
+ if (dataLen != len) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@@ -3650,7 +3654,7 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
return NS_ERROR_FAILURE;
}
- uint8_t *src = aData;
+ uint8_t *src = aArray->Data();
uint8_t *dst = imgsurf->Data();
for (uint32_t j = 0; j < h; j++) {
diff --git a/content/canvas/src/CanvasRenderingContext2D.h b/content/canvas/src/CanvasRenderingContext2D.h
index d0f8fa0..0aff60d 100644
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -21,6 +21,7 @@
#include "mozilla/dom/CanvasGradient.h"
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
#include "mozilla/dom/CanvasPattern.h"
+#include "mozilla/dom/TypedArray.h"
#include "mozilla/gfx/Rect.h"
class nsXULElement;
@@ -443,7 +444,7 @@ protected:
JSObject** aRetval);
nsresult PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
- unsigned char *aData, uint32_t aDataLen,
+ dom::Uint8ClampedArray* aArray,
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
int32_t dirtyWidth, int32_t dirtyHeight);
diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h
index e8e55db..db0c20a 100644
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -585,6 +585,7 @@ public:
WebGLfloat z, WebGLfloat w);
void Uniform1iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform1iv_base(location, arr.Length(), arr.Data());
}
void Uniform1iv(WebGLUniformLocation* location,
@@ -595,6 +596,7 @@ public:
const WebGLint* data);
void Uniform2iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform2iv_base(location, arr.Length(), arr.Data());
}
void Uniform2iv(WebGLUniformLocation* location,
@@ -605,6 +607,7 @@ public:
const WebGLint* data);
void Uniform3iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform3iv_base(location, arr.Length(), arr.Data());
}
void Uniform3iv(WebGLUniformLocation* location,
@@ -615,6 +618,7 @@ public:
const WebGLint* data);
void Uniform4iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform4iv_base(location, arr.Length(), arr.Data());
}
void Uniform4iv(WebGLUniformLocation* location,
@@ -625,6 +629,7 @@ public:
const WebGLint* data);
void Uniform1fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform1fv_base(location, arr.Length(), arr.Data());
}
void Uniform1fv(WebGLUniformLocation* location,
@@ -635,6 +640,7 @@ public:
const WebGLfloat* data);
void Uniform2fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform2fv_base(location, arr.Length(), arr.Data());
}
void Uniform2fv(WebGLUniformLocation* location,
@@ -645,6 +651,7 @@ public:
const WebGLfloat* data);
void Uniform3fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform3fv_base(location, arr.Length(), arr.Data());
}
void Uniform3fv(WebGLUniformLocation* location,
@@ -655,6 +662,7 @@ public:
const WebGLfloat* data);
void Uniform4fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
+ arr.ComputeLengthAndData();
Uniform4fv_base(location, arr.Length(), arr.Data());
}
void Uniform4fv(WebGLUniformLocation* location,
@@ -667,6 +675,7 @@ public:
void UniformMatrix2fv(WebGLUniformLocation* location,
WebGLboolean transpose,
dom::Float32Array &value) {
+ value.ComputeLengthAndData();
UniformMatrix2fv_base(location, transpose, value.Length(), value.Data());
}
void UniformMatrix2fv(WebGLUniformLocation* location,
@@ -682,6 +691,7 @@ public:
void UniformMatrix3fv(WebGLUniformLocation* location,
WebGLboolean transpose,
dom::Float32Array &value) {
+ value.ComputeLengthAndData();
UniformMatrix3fv_base(location, transpose, value.Length(), value.Data());
}
void UniformMatrix3fv(WebGLUniformLocation* location,
@@ -697,6 +707,7 @@ public:
void UniformMatrix4fv(WebGLUniformLocation* location,
WebGLboolean transpose,
dom::Float32Array &value) {
+ value.ComputeLengthAndData();
UniformMatrix4fv_base(location, transpose, value.Length(), value.Data());
}
void UniformMatrix4fv(WebGLUniformLocation* location,
@@ -731,6 +742,7 @@ public:
WebGLfloat x2, WebGLfloat x3);
void VertexAttrib1fv(WebGLuint idx, dom::Float32Array &arr) {
+ arr.ComputeLengthAndData();
VertexAttrib1fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib1fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
@@ -740,6 +752,7 @@ public:
const WebGLfloat* ptr);
void VertexAttrib2fv(WebGLuint idx, dom::Float32Array &arr) {
+ arr.ComputeLengthAndData();
VertexAttrib2fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib2fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
@@ -749,6 +762,7 @@ public:
const WebGLfloat* ptr);
void VertexAttrib3fv(WebGLuint idx, dom::Float32Array &arr) {
+ arr.ComputeLengthAndData();
VertexAttrib3fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib3fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
@@ -758,6 +772,7 @@ public:
const WebGLfloat* ptr);
void VertexAttrib4fv(WebGLuint idx, dom::Float32Array &arr) {
+ arr.ComputeLengthAndData();
VertexAttrib4fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib4fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp
index 6b4c77b..c1f943f 100644
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -431,6 +431,8 @@ WebGLContext::BufferData(WebGLenum target, ArrayBuffer *data, WebGLenum usage)
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
+ data->ComputeLengthAndData();
+
GLenum error = CheckedBufferData(target, data->Length(), data->Data(), usage);
if (error) {
@@ -469,6 +471,8 @@ WebGLContext::BufferData(WebGLenum target, ArrayBufferView& data, WebGLenum usag
InvalidateCachedMinInUseAttribArrayLength();
MakeContextCurrent();
+ data.ComputeLengthAndData();
+
GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
if (error) {
GenerateWarning("bufferData generated error %s", ErrorName(error));
@@ -509,6 +513,8 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
+ data->ComputeLengthAndData();
+
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->Length();
if (!checked_neededByteLength.isValid())
return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
@@ -547,6 +553,8 @@ WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
if (!boundBuffer)
return ErrorInvalidOperation("bufferSubData: no buffer bound!");
+ data.ComputeLengthAndData();
+
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.Length();
if (!checked_neededByteLength.isValid())
return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
@@ -3382,7 +3390,11 @@ WebGLContext::ReadPixels(WebGLint x, WebGLint y, WebGLsizei width,
if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
- uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels->Obj());
+ // Compute length and data. Don't reenter after this point, lest the
+ // precomputed go out of sync with the instant length/data.
+ pixels->ComputeLengthAndData();
+
+ uint32_t dataByteLen = pixels->Length();
if (checked_neededByteLength.value() > dataByteLen)
return ErrorInvalidOperation("readPixels: buffer too small");
@@ -4584,6 +4596,8 @@ WebGLContext::CompressedTexImage2D(WebGLenum target, WebGLint level, WebGLenum i
return;
}
+ view.ComputeLengthAndData();
+
uint32_t byteLength = view.Length();
if (!ValidateCompressedTextureSize(target, level, internalformat, width, height, byteLength, "compressedTexImage2D")) {
return;
@@ -4633,6 +4647,8 @@ WebGLContext::CompressedTexSubImage2D(WebGLenum target, WebGLint level, WebGLint
return;
}
+ view.ComputeLengthAndData();
+
uint32_t byteLength = view.Length();
if (!ValidateCompressedTextureSize(target, level, format, width, height, byteLength, "compressedTexSubImage2D")) {
return;
@@ -5135,10 +5151,23 @@ WebGLContext::TexImage2D(WebGLenum target, WebGLint level,
if (!IsContextStable())
return;
+ void* data;
+ uint32_t length;
+ int jsArrayType;
+ if (!pixels) {
+ data = nullptr;
+ length = 0;
+ jsArrayType = -1;
+ } else {
+ pixels->ComputeLengthAndData();
+
+ data = pixels->Data();
+ length = pixels->Length();
+ jsArrayType = int(JS_GetArrayBufferViewType(pixels->Obj()));
+ }
+
return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
- pixels ? pixels->Data() : 0,
- pixels ? pixels->Length() : 0,
- pixels ? (int)JS_GetArrayBufferViewType(pixels->Obj()) : -1,
+ data, length, jsArrayType,
WebGLTexelConversions::Auto, false);
}
@@ -5156,6 +5185,8 @@ WebGLContext::TexImage2D(WebGLenum target, WebGLint level,
}
Uint8ClampedArray arr(pixels->GetDataObject());
+ arr.ComputeLengthAndData();
+
return TexImage2D_base(target, level, internalformat, pixels->Width(),
pixels->Height(), 4*pixels->Width(), 0,
format, type, arr.Data(), arr.Length(), -1,
@@ -5289,6 +5320,8 @@ WebGLContext::TexSubImage2D(WebGLenum target, WebGLint level,
if (!pixels)
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
+ pixels->ComputeLengthAndData();
+
return TexSubImage2D_base(target, level, xoffset, yoffset,
width, height, 0, format, type,
pixels->Data(), pixels->Length(),
@@ -5309,6 +5342,8 @@ WebGLContext::TexSubImage2D(WebGLenum target, WebGLint level,
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
Uint8ClampedArray arr(pixels->GetDataObject());
+ arr.ComputeLengthAndData();
+
return TexSubImage2D_base(target, level, xoffset, yoffset,
pixels->Width(), pixels->Height(),
4*pixels->Width(), format, type,
diff --git a/content/html/content/public/HTMLAudioElement.h b/content/html/content/public/HTMLAudioElement.h
index 49fcd23..3c19e84 100644
--- a/content/html/content/public/HTMLAudioElement.h
+++ b/content/html/content/public/HTMLAudioElement.h
@@ -63,6 +63,7 @@ public:
uint32_t MozWriteAudio(const Float32Array& aData, ErrorResult& aRv)
{
+ aData.ComputeLengthAndData();
return MozWriteAudio(aData.Data(), aData.Length(), aRv);
}
uint32_t MozWriteAudio(const Sequence<float>& aData, ErrorResult& aRv)
diff --git a/content/media/webaudio/AnalyserNode.cpp b/content/media/webaudio/AnalyserNode.cpp
index d5fbe9c..613852d 100644
--- a/content/media/webaudio/AnalyserNode.cpp
+++ b/content/media/webaudio/AnalyserNode.cpp
@@ -150,6 +150,8 @@ AnalyserNode::GetFloatFrequencyData(Float32Array& aArray)
return;
}
+ aArray.ComputeLengthAndData();
+
float* buffer = aArray.Data();
uint32_t length = std::min(aArray.Length(), mOutputBuffer.Length());
@@ -168,6 +170,8 @@ AnalyserNode::GetByteFrequencyData(Uint8Array& aArray)
const double rangeScaleFactor = 1.0 / (mMaxDecibels - mMinDecibels);
+ aArray.ComputeLengthAndData();
+
unsigned char* buffer = aArray.Data();
uint32_t length = std::min(aArray.Length(), mOutputBuffer.Length());
@@ -183,6 +187,8 @@ AnalyserNode::GetByteFrequencyData(Uint8Array& aArray)
void
AnalyserNode::GetByteTimeDomainData(Uint8Array& aArray)
{
+ aArray.ComputeLengthAndData();
+
unsigned char* buffer = aArray.Data();
uint32_t length = std::min(aArray.Length(), mBuffer.Length());
diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp
index 1bf78ef..3ef2ff4 100644
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -169,18 +169,20 @@ AudioContext::CreateBuffer(JSContext* aJSContext, ArrayBuffer& aBuffer,
return nullptr;
}
+ aBuffer.ComputeLengthAndData();
+
+ uint32_t len = aBuffer.Length();
+ uint8_t* data = aBuffer.Data();
+
// Sniff the content of the media.
// Failed type sniffing will be handled by SyncDecodeMedia.
nsAutoCString contentType;
- NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr,
- aBuffer.Data(), aBuffer.Length(),
- contentType);
+ NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, len, contentType);
nsRefPtr<WebAudioDecodeJob> job =
new WebAudioDecodeJob(contentType, this, aBuffer);
- if (mDecoder.SyncDecodeMedia(contentType.get(),
- aBuffer.Data(), aBuffer.Length(), *job) &&
+ if (mDecoder.SyncDecodeMedia(contentType.get(), data, len, *job) &&
job->mOutput) {
nsRefPtr<AudioBuffer> buffer = job->mOutput.forget();
if (aMixToMono) {
@@ -342,6 +344,9 @@ AudioContext::CreatePeriodicWave(const Float32Array& aRealData,
const Float32Array& aImagData,
ErrorResult& aRv)
{
+ aRealData.ComputeLengthAndData();
+ aImagData.ComputeLengthAndData();
+
if (aRealData.Length() != aImagData.Length() ||
aRealData.Length() == 0 ||
aRealData.Length() > 4096) {
@@ -369,6 +374,8 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
DecodeSuccessCallback& aSuccessCallback,
const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback)
{
+ aBuffer.ComputeLengthAndData();
+
// Sniff the content of the media.
// Failed type sniffing will be handled by AsyncDecodeMedia.
nsAutoCString contentType;
diff --git a/content/media/webaudio/AudioParam.h b/content/media/webaudio/AudioParam.h
index e735b59..e6d95b0 100644
--- a/content/media/webaudio/AudioParam.h
+++ b/content/media/webaudio/AudioParam.h
@@ -57,6 +57,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
+ aValues.ComputeLengthAndData();
AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
aStartTime, aDuration, aRv);
mCallback(mNode);
diff --git a/content/media/webaudio/BiquadFilterNode.cpp b/content/media/webaudio/BiquadFilterNode.cpp
index fe45106..fa4f1d1 100644
--- a/content/media/webaudio/BiquadFilterNode.cpp
+++ b/content/media/webaudio/BiquadFilterNode.cpp
@@ -247,6 +247,10 @@ BiquadFilterNode::GetFrequencyResponse(const Float32Array& aFrequencyHz,
Float32Array& aMagResponse,
Float32Array& aPhaseResponse)
{
+ aFrequencyHz.ComputeLengthAndData();
+ aMagResponse.ComputeLengthAndData();
+ aPhaseResponse.ComputeLengthAndData();
+
uint32_t length = std::min(std::min(aFrequencyHz.Length(), aMagResponse.Length()),
aPhaseResponse.Length());
if (!length) {
diff --git a/content/media/webaudio/WaveShaperNode.cpp b/content/media/webaudio/WaveShaperNode.cpp
index 22df163..fa39637 100644
--- a/content/media/webaudio/WaveShaperNode.cpp
+++ b/content/media/webaudio/WaveShaperNode.cpp
@@ -125,6 +125,8 @@ WaveShaperNode::SetCurve(const Float32Array* aCurve)
if (aCurve) {
mCurve = aCurve->Obj();
+ aCurve->ComputeLengthAndData();
+
curve.SetLength(aCurve->Length());
PodCopy(curve.Elements(), aCurve->Data(), aCurve->Length());
} else {
diff --git a/dom/bindings/TypedArray.h b/dom/bindings/TypedArray.h
index 6531f2f..c7c2bbd 100644
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -20,30 +20,43 @@ namespace dom {
* or array buffer object.
*/
template<typename T,
- JSObject* UnboxArray(JSObject*, uint32_t*, T**)>
+ JSObject* UnwrapArray(JSObject*),
+ void GetLengthAndData(JSObject*, uint32_t*, T**)>
struct TypedArray_base {
TypedArray_base(JSObject* obj)
+ : mObj(obj),
+ mData(NULL),
+ mLength(0),
+ mComputed(false)
{
- mObj = UnboxArray(obj, &mLength, &mData);
+ MOZ_ASSERT(obj != NULL);
}
private:
- T* mData;
- uint32_t mLength;
JSObject* mObj;
+ mutable T* mData;
+ mutable uint32_t mLength;
+ mutable bool mComputed;
public:
+ inline bool Init(JSObject* obj)
+ {
+ MOZ_ASSERT(!inited());
+ DoInit(obj);
+ return inited();
+ }
+
inline bool inited() const {
return !!mObj;
}
inline T *Data() const {
- MOZ_ASSERT(inited());
+ MOZ_ASSERT(mComputed);
return mData;
}
inline uint32_t Length() const {
- MOZ_ASSERT(inited());
+ MOZ_ASSERT(mComputed);
return mLength;
}
@@ -51,16 +64,31 @@ public:
MOZ_ASSERT(inited());
return mObj;
}
+
+ inline void ComputeLengthAndData() const
+ {
+ MOZ_ASSERT(inited());
+ MOZ_ASSERT(!mComputed);
+ GetLengthAndData(mObj, &mLength, &mData);
+ mComputed = true;
+ }
+
+protected:
+ inline void DoInit(JSObject* obj)
+ {
+ mObj = UnwrapArray(obj);
+ }
};
template<typename T,
+ JSObject* UnwrapArray(JSObject*),
T* GetData(JSObject*),
- JSObject* UnboxArray(JSObject*, uint32_t*, T**),
+ void GetLengthAndData(JSObject*, uint32_t*, T**),
JSObject* CreateNew(JSContext*, uint32_t)>
-struct TypedArray : public TypedArray_base<T,UnboxArray> {
+struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
TypedArray(JSObject* obj) :
- TypedArray_base<T,UnboxArray>(obj)
+ TypedArray_base<T, UnwrapArray, GetLengthAndData>(obj)
{}
static inline JSObject*
@@ -83,37 +111,37 @@ struct TypedArray : public TypedArray_base<T,UnboxArray> {
}
};
-typedef TypedArray<int8_t, JS_GetInt8ArrayData, JS_GetObjectAsInt8Array,
- JS_NewInt8Array>
+typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData,
+ js::GetInt8ArrayLengthAndData, JS_NewInt8Array>
Int8Array;
-typedef TypedArray<uint8_t, JS_GetUint8ArrayData,
- JS_GetObjectAsUint8Array, JS_NewUint8Array>
+typedef TypedArray<uint8_t, js::UnwrapUint8Array, JS_GetUint8ArrayData,
+ js::GetUint8ArrayLengthAndData, JS_NewUint8Array>
Uint8Array;
-typedef TypedArray<uint8_t, JS_GetUint8ClampedArrayData,
- JS_GetObjectAsUint8ClampedArray, JS_NewUint8ClampedArray>
+typedef TypedArray<uint8_t, js::UnwrapUint8ClampedArray, JS_GetUint8ClampedArrayData,
+ js::GetUint8ClampedArrayLengthAndData, JS_NewUint8ClampedArray>
Uint8ClampedArray;
-typedef TypedArray<int16_t, JS_GetInt16ArrayData,
- JS_GetObjectAsInt16Array, JS_NewInt16Array>
+typedef TypedArray<int16_t, js::UnwrapInt16Array, JS_GetInt16ArrayData,
+ js::GetInt16ArrayLengthAndData, JS_NewInt16Array>
Int16Array;
-typedef TypedArray<uint16_t, JS_GetUint16ArrayData,
- JS_GetObjectAsUint16Array, JS_NewUint16Array>
+typedef TypedArray<uint16_t, js::UnwrapUint16Array, JS_GetUint16ArrayData,
+ js::GetUint16ArrayLengthAndData, JS_NewUint16Array>
Uint16Array;
-typedef TypedArray<int32_t, JS_GetInt32ArrayData,
- JS_GetObjectAsInt32Array, JS_NewInt32Array>
+typedef TypedArray<int32_t, js::UnwrapInt32Array, JS_GetInt32ArrayData,
+ js::GetInt32ArrayLengthAndData, JS_NewInt32Array>
Int32Array;
-typedef TypedArray<uint32_t, JS_GetUint32ArrayData,
- JS_GetObjectAsUint32Array, JS_NewUint32Array>
+typedef TypedArray<uint32_t, js::UnwrapUint32Array, JS_GetUint32ArrayData,
+ js::GetUint32ArrayLengthAndData, JS_NewUint32Array>
Uint32Array;
-typedef TypedArray<float, JS_GetFloat32ArrayData,
- JS_GetObjectAsFloat32Array, JS_NewFloat32Array>
+typedef TypedArray<float, js::UnwrapFloat32Array, JS_GetFloat32ArrayData,
+ js::GetFloat32ArrayLengthAndData, JS_NewFloat32Array>
Float32Array;
-typedef TypedArray<double, JS_GetFloat64ArrayData,
- JS_GetObjectAsFloat64Array, JS_NewFloat64Array>
+typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData,
+ js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
Float64Array;
-typedef TypedArray_base<uint8_t, JS_GetObjectAsArrayBufferView>
+typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData>
ArrayBufferView;
-typedef TypedArray<uint8_t, JS_GetArrayBufferData,
- JS_GetObjectAsArrayBuffer, JS_NewArrayBuffer>
+typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
+ js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
ArrayBuffer;
} // namespace dom
diff --git a/dom/encoding/TextDecoder.h b/dom/encoding/TextDecoder.h
index d309209..3db00a4 100644
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -66,6 +66,7 @@ public:
const TextDecodeOptions& aOptions,
nsAString& aOutDecodedString,
ErrorResult& aRv) {
+ aView.ComputeLengthAndData();
TextDecoderBase::Decode(reinterpret_cast<char*>(aView.Data()),
aView.Length(), aOptions.mStream,
aOutDecodedString, aRv);
diff --git a/dom/workers/TextDecoder.h b/dom/workers/TextDecoder.h
index 6c88a70..205afc5 100644
--- a/dom/workers/TextDecoder.h
+++ b/dom/workers/TextDecoder.h
@@ -49,6 +49,7 @@ public:
const TextDecodeOptionsWorkers& aOptions,
nsAString& aOutDecodedString,
ErrorResult& aRv) {
+ aView.ComputeLengthAndData();
TextDecoderBase::Decode(reinterpret_cast<char*>(aView.Data()),
aView.Length(), aOptions.mStream,
aOutDecodedString, aRv);
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index 24cb2d7..ce6d633 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -999,6 +999,49 @@ js::IsAsmJSFunction(JSContext *cx, unsigned argc, Value *vp)
}
#endif
+static JSBool
+Neuter(JSContext *cx, unsigned argc, jsval *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (args.length() != 2) {
+ JS_ReportError(cx, "wrong number of arguments to neuter()");
+ return false;
+ }
+
+ RootedObject obj(cx);
+ if (!JS_ValueToObject(cx, args[0], obj.address()))
+ return false;
+
+ if (!obj) {
+ JS_ReportError(cx, "neuter must be passed an object");
+ return false;
+ }
+
+ NeuterDataDisposition changeData;
+ RootedValue v(cx, args[1]);
+ RootedString str(cx, ToString<CanGC>(cx, v));
+ if (!str)
+ return false;
+ JSAutoByteString dataDisposition(cx, str);
+ if (!dataDisposition)
+ return false;
+ if (strcmp(dataDisposition.ptr(), "same-data") == 0) {
+ changeData = KeepData;
+ } else if (strcmp(dataDisposition.ptr(), "change-data") == 0) {
+ changeData = ChangeData;
+ } else {
+ JS_ReportError(cx, "unknown parameter 2 to neuter()");
+ return false;
+ }
+
+ if (!js::NeuterArrayBuffer(cx, obj, changeData))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
static JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'compartment')",
@@ -1177,6 +1220,13 @@ static JSFunctionSpecWithHelp TestingFunctions[] = {
"getObjectMetadata(obj)",
" Get the metadata for an object."),
+ JS_FN_HELP("neuter", Neuter, 1, 0,
+"neuter(buffer, \"change-data\"|\"same-data\")",
+" Neuter the given ArrayBuffer object as if it had been transferred to a\n"
+" WebWorker. \"change-data\" will update the internal data pointer.\n"
+" \"same-data\" will leave it set to its original value, to mimic eg\n"
+" asm.js ArrayBuffer neutering."),
+
JS_FS_HELP_END
};
diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
index a0c70f5..2ceaf71 100644
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6446,29 +6446,12 @@ IonBuilder::jsop_getelem_dense()
MInstruction *
IonBuilder::getTypedArrayLength(MDefinition *obj)
{
- if (obj->isConstant() && obj->toConstant()->value().isObject()) {
- JSObject *array = &obj->toConstant()->value().toObject();
- int32_t length = (int32_t) TypedArray::length(array);
- obj->setFoldedUnchecked();
- return MConstant::New(Int32Value(length));
- }
return MTypedArrayLength::New(obj);
}
MInstruction *
IonBuilder::getTypedArrayElements(MDefinition *obj)
{
- if (obj->isConstant() && obj->toConstant()->value().isObject()) {
- JSObject *array = &obj->toConstant()->value().toObject();
- void *data = TypedArray::viewData(array);
-
- // The 'data' pointer can change in rare circumstances
- // (ArrayBufferObject::changeContents).
- types::HeapTypeSet::WatchObjectStateChange(cx, array->getType(cx));
-
- obj->setFoldedUnchecked();
- return MConstantElements::New(data);
- }
return MTypedArrayElements::New(obj);
}
@@ -6504,49 +6487,6 @@ IonBuilder::jsop_getelem_typed_static(bool *psucceeded)
if (!LIRGenerator::allowStaticTypedArrayAccesses())
return true;
- MDefinition *id = current->peek(-1);
- MDefinition *obj = current->peek(-2);
-
- if (ElementAccessHasExtraIndexedProperty(cx, obj))
- return true;
-
- if (!obj->resultTypeSet())
- return true;
- JSObject *typedArray = obj->resultTypeSet()->getSingleton();
- if (!typedArray)
- return true;
- JS_ASSERT(typedArray->isTypedArray());
-
- ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(typedArray);
-
- MDefinition *ptr = convertShiftToMaskForStaticTypedArray(id, viewType);
- if (!ptr)
- return true;
-
- obj->setFoldedUnchecked();
-
- MLoadTypedArrayElementStatic *load = MLoadTypedArrayElementStatic::New(typedArray, ptr);
- current->add(load);
-
- // The load is infallible if an undefined result will be coerced to the
- // appropriate numeric type if the read is out of bounds. The truncation
- // analysis picks up some of these cases, but is incomplete with respect
- // to others. For now, sniff the bytecode for simple patterns following
- // the load which guarantee a truncation or numeric conversion.
- if (viewType == ArrayBufferView::TYPE_FLOAT32 || viewType == ArrayBufferView::TYPE_FLOAT64) {
- jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
- if (*next == JSOP_POS)
- load->setInfallible();
- } else {
- jsbytecode *next = pc + JSOP_GETELEM_LENGTH;
- if (*next == JSOP_ZERO && *(next + JSOP_ZERO_LENGTH) == JSOP_BITOR)
- load->setInfallible();
- }
-
- current->popn(2);
- current->push(load);
-
- *psucceeded = true;
return true;
}
@@ -6854,37 +6794,7 @@ IonBuilder::jsop_setelem_typed_static(MDefinition *obj, MDefinition *id, MDefini
if (!LIRGenerator::allowStaticTypedArrayAccesses())
return true;
- if (ElementAccessHasExtraIndexedProperty(cx, obj))
- return true;
-
- if (!obj->resultTypeSet())
- return true;
- JSObject *typedArray = obj->resultTypeSet()->getSingleton();
- if (!typedArray)
- return true;
- JS_ASSERT(typedArray->isTypedArray());
-
- ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(typedArray);
-
- MDefinition *ptr = convertShiftToMaskForStaticTypedArray(id, viewType);
- if (!ptr)
- return true;
-
- obj->setFoldedUnchecked();
-
- // Clamp value to [0, 255] for Uint8ClampedArray.
- MDefinition *toWrite = value;
- if (viewType == ArrayBufferView::TYPE_UINT8_CLAMPED) {
- toWrite = MClampToUint8::New(value);
- current->add(toWrite->toInstruction());
- }
-
- MInstruction *store = MStoreTypedArrayElementStatic::New(typedArray, ptr, toWrite);
- current->add(store);
- current->push(value);
-
- *psucceeded = true;
- return resumeAfter(store);
+ return true;
}
bool
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 96ba2d4..02ba6d7 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -211,14 +211,16 @@ class AliasSet {
FixedSlot = 1 << 3, // A member of obj->fixedSlots().
TypedArrayElement = 1 << 4, // A typed array element.
DOMProperty = 1 << 5, // A DOM property
- Last = DOMProperty,
+ TypedArrayLength = 1 << 6, // A typed array's length
+ Last = TypedArrayLength,
Any = Last | (Last - 1),
- NumCategories = 6,
+ NumCategories = 7,
// Indicates load or store.
Store_ = 1 << 31
};
+
AliasSet(uint32_t flags)
: flags_(flags)
{
@@ -4340,9 +4342,7 @@ class MTypedArrayLength
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
- // The typed array |length| property is immutable, so there is no
- // implicit dependency.
- return AliasSet::None();
+ return AliasSet::Load(AliasSet::TypedArrayLength);
}
};
diff --git a/js/src/js.msg b/js/src/js.msg
index 4047035..05807e0 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -241,11 +241,11 @@ MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
MSG_DEF(JSMSG_UNUSED189, 189, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "")
-MSG_DEF(JSMSG_UNUSED191, 191, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_BAD_INDEX, 191, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
MSG_DEF(JSMSG_UNUSED194, 194, 0, JSEXN_NONE, "")
-MSG_DEF(JSMSG_UNUSED195, 195, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 195, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_UNUSED196, 196, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 197, 0, JSEXN_ERR, "internal error while computing Intl data")
MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 198, 0, JSEXN_ERR, "internal error getting the default locale")
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index d9840b1..da447a5 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -7,6 +7,8 @@
#ifndef jsfriendapi_h
#define jsfriendapi_h
+#include "mozilla/Casting.h"
+
#include "jsclass.h"
#include "jspubtd.h"
#include "jsprvtd.h"
@@ -1289,6 +1291,93 @@ extern JS_FRIEND_API(JSBool)
JS_IsFloat64Array(JSObject *obj);
/*
+ * Test for specific typed array types (ArrayBufferView subtypes) and return
+ * the unwrapped object if so, else nullptr. Never throws.
+ */
+
+namespace js {
+
+extern JS_FRIEND_API(JSObject *)
+UnwrapInt8Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapUint8Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapUint8ClampedArray(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapInt16Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapUint16Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapInt32Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapUint32Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapFloat32Array(JSObject *obj);
+extern JS_FRIEND_API(JSObject *)
+UnwrapFloat64Array(JSObject *obj);
+
+extern JS_FRIEND_API(JSObject *)
+UnwrapArrayBuffer(JSObject *obj);
+
+extern JS_FRIEND_API(JSObject *)
+UnwrapArrayBufferView(JSObject *obj);
+
+namespace detail {
+
+extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr;
+
+const size_t TypedArrayLengthSlot = 5;
+
+} // namespace detail
+
+/*
+ * Test for specific typed array types (ArrayBufferView subtypes) and return
+ * the unwrapped object if so, else nullptr. Never throws.
+ */
+
+#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
+inline void \
+Get ## Type ## ArrayLengthAndData(JSObject *obj, uint32_t *length, type **data) \
+{ \
+ JS_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \
+ const JS::Value &slot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
+ *length = mozilla::SafeCast<uint32_t>(slot.toInt32()); \
+ *data = static_cast<type*>(GetObjectPrivate(obj)); \
+}
+
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float)
+JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double)
+
+#undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR
+
+// This one isn't inlined because it's rather tricky (by dint of having to deal
+// with a dozen-plus classes and varying slot layouts.
+extern JS_FRIEND_API(void)
+GetArrayBufferViewLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data);
+
+// This one isn't inlined because there are a bunch of different ArrayBuffer
+// classes that would have to be individually handled here.
+extern JS_FRIEND_API(void)
+GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data);
+
+} // namespace js
+
+/*
* Unwrap Typed arrays all at once. Return NULL without throwing if the object
* cannot be viewed as the correct typed array, or the typed array object on
* success, filling both outparameters.
@@ -1446,6 +1535,28 @@ JS_GetArrayBufferViewData(JSObject *obj);
extern JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSObject *obj);
+typedef enum {
+ ChangeData,
+ KeepData
+} NeuterDataDisposition;
+
+namespace js {
+
+/*
+ * Set an ArrayBuffer's length to 0 and neuter all of its views.
+ *
+ * The |changeData| argument is a hint to inform internal behavior with respect
+ * to the internal pointer to the ArrayBuffer's data after being neutered.
+ * There is no guarantee it will be respected. But if it is respected, the
+ * ArrayBuffer's internal data pointer will, or will not, have changed
+ * accordingly.
+ */
+extern JS_FRIEND_API(bool)
+NeuterArrayBuffer(JSContext *cx, JS::HandleObject obj,
+ NeuterDataDisposition changeData);
+
+} /* namespace js */
+
/*
* Check whether obj supports JS_GetDataView* APIs.
*/
diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp
index 9d02d06..a78edd4 100644
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -577,9 +577,12 @@ JSObject *
ArrayBufferObject::createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
uint32_t begin, uint32_t end)
{
- JS_ASSERT(begin <= arrayBuffer.byteLength());
- JS_ASSERT(end <= arrayBuffer.byteLength());
- JS_ASSERT(begin <= end);
+ uint32_t bufLength = arrayBuffer.byteLength();
+ if (begin > bufLength || end > bufLength || begin > end) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPE_ERR_BAD_ARGS);
+ return NULL;
+ }
+
uint32_t length = end - begin;
if (arrayBuffer.hasData())
@@ -620,8 +623,8 @@ ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp
}
bool
-ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
- uint8_t **data)
+ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, NeuterDataDisposition changeData,
+ void **contents, uint8_t **data)
{
MOZ_ASSERT(cx);
@@ -635,7 +638,7 @@ ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
// If the ArrayBuffer's elements are transferrable, transfer ownership
// directly. Otherwise we have to copy the data into new elements.
- bool stolen = buffer.hasStealableContents();
+ bool stolen = buffer.hasStealableContents() && changeData == ChangeData;
if (stolen) {
newHeader = AllocateArrayBufferContents(cx, byteLen, NULL);
if (!newHeader)
@@ -1190,13 +1193,15 @@ js::IsDataView(JSObject* obj)
}
void
-TypedArray::neuter(JSObject *tarray)
+TypedArray::neuter(JSObject *view)
{
- JS_ASSERT(tarray->isTypedArray());
- tarray->setSlot(LENGTH_SLOT, Int32Value(0));
- tarray->setSlot(BYTELENGTH_SLOT, Int32Value(0));
- tarray->setSlot(BYTEOFFSET_SLOT, Int32Value(0));
- tarray->setPrivate(NULL);
+ if (view->isTypedArray())
+ view->setSlot(LENGTH_SLOT, Int32Value(0));
+ else
+ MOZ_ASSERT(view->hasClass(&DataViewObject::class_));
+ view->setSlot(BYTELENGTH_SLOT, Int32Value(0));
+ view->setSlot(BYTEOFFSET_SLOT, Int32Value(0));
+ view->setPrivate(NULL);
}
JSBool
@@ -2023,20 +2028,26 @@ class TypedArrayTemplate
uint32_t srcEnd;
uint32_t dest;
- uint32_t length = TypedArray::length(tarray);
- if (!ToClampedIndex(cx, args[0], length, &srcBegin) ||
- !ToClampedIndex(cx, args[1], length, &srcEnd) ||
- !ToClampedIndex(cx, args[2], length, &dest) ||
+ uint32_t originalLength = TypedArray::length(tarray);
+ if (!ToClampedIndex(cx, args[0], originalLength, &srcBegin) ||
+ !ToClampedIndex(cx, args[1], originalLength, &srcEnd) ||
+ !ToClampedIndex(cx, args[2], originalLength, &dest) ||
srcBegin > srcEnd)
{
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
+ if (srcBegin > srcEnd) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDEX);
+ return false;
+ }
+
+ uint32_t lengthDuringMove = TypedArray::length(tarray); // beware ToClampedIndex
uint32_t nelts = srcEnd - srcBegin;
- JS_ASSERT(dest + nelts >= dest);
- if (dest + nelts > length) {
+ MOZ_ASSERT(dest <= INT32_MAX, "size limited to 2**31");
+ MOZ_ASSERT(nelts <= INT32_MAX, "size limited to 2**31");
+ if (dest + nelts > lengthDuringMove || srcEnd > lengthDuringMove) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
@@ -2114,8 +2125,7 @@ class TypedArrayTemplate
if (!GetLengthProperty(cx, arg0, &len))
return false;
- // avoid overflow; we know that offset <= length
- if (len > length(tarray) - offset) {
+ if (uint32_t(offset) > length(tarray) || len > length(tarray) - offset) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
@@ -2268,7 +2278,8 @@ class TypedArrayTemplate
static const NativeType
getIndex(JSObject *obj, uint32_t index)
{
- return *(static_cast<const NativeType*>(viewData(obj)) + index);
+ MOZ_ASSERT(index < length(obj));
+ return static_cast<const NativeType*>(viewData(obj))[index];
}
static void
@@ -2284,13 +2295,14 @@ class TypedArrayTemplate
{
JS_ASSERT(tarray);
- JS_ASSERT(begin <= length(tarray));
- JS_ASSERT(end <= length(tarray));
+ if (begin > length(tarray) || end > length(tarray) || begin > end) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDEX);
+ return NULL;
+ }
RootedObject bufobj(cx, buffer(tarray));
JS_ASSERT(bufobj);
- JS_ASSERT(begin <= end);
uint32_t length = end - begin;
JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
@@ -2505,53 +2517,54 @@ class TypedArrayTemplate
return false;
js_memcpy(srcbuf, viewData(tarray), byteLength);
+ uint32_t len = length(tarray);
switch (type(tarray)) {
case TypedArray::TYPE_INT8: {
int8_t *src = (int8_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_UINT8_CLAMPED: {
uint8_t *src = (uint8_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_INT16: {
int16_t *src = (int16_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_UINT16: {
uint16_t *src = (uint16_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_INT32: {
int32_t *src = (int32_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_UINT32: {
uint32_t *src = (uint32_t*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_FLOAT32: {
float *src = (float*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
case TypedArray::TYPE_FLOAT64: {
double *src = (double*) srcbuf;
- for (unsigned i = 0; i < length(tarray); ++i)
+ for (unsigned i = 0; i < len; ++i)
*dest++ = NativeType(*src++);
break;
}
@@ -2822,21 +2835,17 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
return construct(cx, bufobj, args, NullPtr());
}
-/* static */ bool
-DataViewObject::getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
- CallArgs args, size_t typeSize, uint8_t **data)
+template <typename NativeType>
+/* static */ uint8_t *
+DataViewObject::getDataPointer(JSContext *cx, Handle<DataViewObject*> obj, uint32_t offset)
{
- uint32_t offset;
- JS_ASSERT(args.length() > 0);
- if (!ToUint32(cx, args[0], &offset))
- return false;
- if (offset > UINT32_MAX - typeSize || offset + typeSize > obj->byteLength()) {
+ const size_t TypeSize = sizeof(NativeType);
+ if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
- return false;
+ return NULL;
}
- *data = static_cast<uint8_t*>(obj->dataPointer()) + offset;
- return true;
+ return static_cast<uint8_t*>(obj->dataPointer()) + offset;
}
static inline bool
@@ -2924,11 +2933,17 @@ DataViewObject::read(JSContext *cx, Handle<DataViewObject*> obj,
return false;
}
- uint8_t *data;
- if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
+ uint32_t offset;
+ if (!ToUint32(cx, args[0], &offset))
return false;
bool fromLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
+
+ uint8_t *data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
+ SkipRoot skipData(cx, &data);
+ if (!data)
+ return false;
+
DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(fromLittleEndian));
return true;
}
@@ -2976,9 +2991,8 @@ DataViewObject::write(JSContext *cx, Handle<DataViewObject*> obj,
return false;
}
- uint8_t *data;
- SkipRoot skipData(cx, &data);
- if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
+ uint32_t offset;
+ if (!ToUint32(cx, args[0], &offset))
return false;
NativeType value;
@@ -2986,6 +3000,12 @@ DataViewObject::write(JSContext *cx, Handle<DataViewObject*> obj,
return false;
bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
+
+ uint8_t *data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
+ SkipRoot skipData(cx, &data);
+ if (!data)
+ return false;
+
DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(toLittleEndian));
return true;
}
@@ -3449,7 +3469,19 @@ const JSFunctionSpec _typedArray::jsfuncs[] = { \
return false; \
Class *clasp = obj->getClass(); \
return (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
- }
+ } \
+ JS_FRIEND_API(JSObject *) js::Unwrap ## Name ## Array(JSObject *obj) \
+ { \
+ obj = CheckedUnwrap(obj); \
+ if (!obj) \
+ return NULL; \
+ const Class *clasp = obj->getClass(); \
+ if (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]) \
+ return obj; \
+ return NULL; \
+ } \
+ JS_FRIEND_DATA(const js::Class* const) js::detail::Name ## ArrayClassPtr = \
+ &js::TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()];
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
@@ -3918,6 +3950,14 @@ JS_IsArrayBufferObject(JSObject *obj)
return obj ? obj->is<ArrayBufferObject>() : false;
}
+JS_FRIEND_API(JSObject *)
+js::UnwrapArrayBuffer(JSObject *obj)
+{
+ if (JSObject *unwrapped = CheckedUnwrap(obj))
+ return unwrapped->is<ArrayBufferObject>() ? unwrapped : NULL;
+ return NULL;
+}
+
JS_FRIEND_API(JSBool)
JS_IsTypedArrayObject(JSObject *obj)
{
@@ -3932,6 +3972,16 @@ JS_IsArrayBufferViewObject(JSObject *obj)
return obj ? (obj->isTypedArray() || obj->is<DataViewObject>()) : false;
}
+JS_FRIEND_API(JSObject *)
+js::UnwrapArrayBufferView(JSObject *obj)
+{
+ if (JSObject *unwrapped = CheckedUnwrap(obj)) {
+ if (unwrapped->isTypedArray() || unwrapped->is<DataViewObject>())
+ return unwrapped;
+ }
+ return NULL;
+}
+
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj)
{
@@ -3951,6 +4001,24 @@ JS_GetArrayBufferData(JSObject *obj)
return buffer.dataPointer();
}
+JS_FRIEND_API(bool)
+js::NeuterArrayBuffer(JSContext *cx, HandleObject obj,
+ NeuterDataDisposition changeData)
+{
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportError(cx, "ArrayBuffer object required");
+ return false;
+ }
+
+ void *contents;
+ uint8_t *data;
+ if (!ArrayBufferObject::stealContents(cx, obj, changeData, &contents, &data))
+ return false;
+
+ JS_free(cx, contents);
+ return true;
+}
+
JS_FRIEND_API(JSObject *)
JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
{
@@ -4010,7 +4078,7 @@ JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
return false;
}
- if (!ArrayBufferObject::stealContents(cx, obj, contents, data))
+ if (!ArrayBufferObject::stealContents(cx, obj, ChangeData, contents, data))
return false;
return true;
@@ -4229,6 +4297,18 @@ JS_GetArrayBufferViewByteLength(JSObject *obj)
: TypedArray::byteLengthValue(obj).toInt32();
}
+JS_FRIEND_API(void)
+js::GetArrayBufferViewLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+ MOZ_ASSERT(obj->is<DataViewObject>() || obj->isTypedArray());
+
+ *length = obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().byteLength()
+ : TypedArray::byteLength(obj);
+
+ *data = static_cast<uint8_t*>(obj->getPrivate());
+}
+
JS_FRIEND_API(JSObject *)
JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
{
@@ -4259,3 +4339,11 @@ JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
return obj;
}
+
+JS_FRIEND_API(void)
+js::GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+ MOZ_ASSERT(obj->is<ArrayBufferObject>());
+ *length = obj->as<ArrayBufferObject>().byteLength();
+ *data = obj->as<ArrayBufferObject>().dataPointer();
+}
diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h
index 4751d53..07d7f80 100644
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -9,6 +9,7 @@
#include "jsapi.h"
#include "jsclass.h"
+#include "jsfriendapi.h"
#include "jsobj.h"
#include "gc/Barrier.h"
@@ -155,8 +156,8 @@ class ArrayBufferObject : public JSObject
return !isNeutered();
}
- static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
- uint8_t **data);
+ static bool stealContents(JSContext *cx, JSObject *obj, NeuterDataDisposition changeData,
+ void **contents, uint8_t **data);
static inline void setElementsHeader(js::ObjectElements *header, uint32_t bytes);
static inline uint32_t getElementsHeaderInitializedLength(const js::ObjectElements *header);
@@ -308,7 +309,7 @@ struct TypedArray : public BufferView {
public:
static bool isArrayIndex(JSObject *obj, jsid id, uint32_t *ip = NULL);
- static void neuter(JSObject *tarray);
+ static void neuter(JSObject *view);
static inline uint32_t slotWidth(int atype);
static inline int slotWidth(JSObject *obj);
@@ -323,6 +324,9 @@ struct TypedArray : public BufferView {
static int dataOffset();
};
+MOZ_STATIC_ASSERT(js::detail::TypedArrayLengthSlot == TypedArray::LENGTH_SLOT,
+ "bad inlined constant in jsfriendapi.h");
+
inline bool
IsTypedArrayClass(const Class *clasp)
{
@@ -376,6 +380,10 @@ private:
static inline bool is(const Value &v);
+ template <typename NativeType>
+ static uint8_t *
+ getDataPointer(JSContext *cx, Handle<DataViewObject*> obj, uint32_t offset);
+
template<Value ValueGetter(DataViewObject &view)>
static bool
getterImpl(JSContext *cx, CallArgs args);
@@ -459,8 +467,6 @@ private:
inline void *dataPointer();
inline bool hasBuffer() const;
static JSObject *initClass(JSContext *cx);
- static bool getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
- CallArgs args, size_t typeSize, uint8_t **data);
template<typename NativeType>
static bool read(JSContext *cx, Handle<DataViewObject*> obj,
CallArgs &args, NativeType *val, const char *method);
diff --git a/js/src/jstypedarrayinlines.h b/js/src/jstypedarrayinlines.h
index f26e9cc..6c8bf75 100644
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -129,6 +129,7 @@ inline void *
TypedArray::viewData(JSObject *obj)
{
JS_ASSERT(obj->isTypedArray());
+ // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
return (void *)obj->getPrivate(DATA_SLOT);
}
@@ -222,6 +223,13 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
RootedObject proto(cx, protoArg);
RootedObject obj(cx);
+ // This is overflow-safe: 2 * INT32_MAX is still a valid uint32_t.
+ if (byteOffset + byteLength > arrayBuffer->byteLength()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+ return nullptr;
+
+ }
+
NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
obj = NewBuiltinClassInstance(cx, &class_, newKind);
if (!obj)
diff --git a/netwerk/base/src/ArrayBufferInputStream.cpp b/netwerk/base/src/ArrayBufferInputStream.cpp
index 0daa1c5..16322d9 100644
--- a/netwerk/base/src/ArrayBufferInputStream.cpp
+++ b/netwerk/base/src/ArrayBufferInputStream.cpp
@@ -88,6 +88,17 @@ ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
}
uint32_t remaining = mBufferLength - mPos;
+ if (!mArrayBuffer.isUndefined()) {
+ JSObject* buf = &mArrayBuffer.toObject();
+ uint32_t byteLength = JS_GetArrayBufferByteLength(buf);
+ if (byteLength == 0 && remaining != 0) {
+ mClosed = true;
+ return NS_BASE_STREAM_CLOSED;
+ }
+ } else {
+ MOZ_ASSERT(remaining == 0, "stream inited incorrectly");
+ }
+
if (!remaining) {
*result = 0;
return NS_OK;
diff --git a/xpcom/io/nsBinaryStream.cpp b/xpcom/io/nsBinaryStream.cpp
index 8c2cc23..24b6ab3 100644
--- a/xpcom/io/nsBinaryStream.cpp
+++ b/xpcom/io/nsBinaryStream.cpp
@@ -17,8 +17,15 @@
* @See nsIBinaryInputStream
* @See nsIBinaryOutputStream
*/
+#include <algorithm>
#include <string.h>
+
#include "nsBinaryStream.h"
+
+#include "mozilla/Endian.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/Scoped.h"
+
#include "nsCRT.h"
#include "prlong.h"
#include "nsString.h"
@@ -26,11 +33,13 @@
#include "nsIClassInfo.h"
#include "nsComponentManagerUtils.h"
#include "nsIURI.h" // for NS_IURI_IID
-#include "mozilla/Endian.h"
#include "jsapi.h"
#include "jsfriendapi.h"
+using mozilla::PodCopy;
+using mozilla::ScopedDeleteArray;
+
NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream)
NS_IMETHODIMP
@@ -720,22 +729,49 @@ nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, const JS::Value& aBuffer,
return NS_ERROR_FAILURE;
}
JS::RootedObject buffer(cx, &aBuffer.toObject());
- if (!JS_IsArrayBufferObject(buffer) ||
- JS_GetArrayBufferByteLength(buffer) < aLength) {
+ if (!JS_IsArrayBufferObject(buffer)) {
return NS_ERROR_FAILURE;
}
- uint8_t* data = JS_GetArrayBufferData(&aBuffer.toObject());
- if (!data) {
+
+ uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer);
+ if (bufferLength < aLength) {
return NS_ERROR_FAILURE;
}
- uint32_t bytesRead;
- nsresult rv = Read(reinterpret_cast<char*>(data), aLength, &bytesRead);
- NS_ENSURE_SUCCESS(rv, rv);
- if (bytesRead != aLength) {
+ char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(buffer));
+ if (!data) {
return NS_ERROR_FAILURE;
}
- return NS_OK;
+
+ uint32_t bufSize = std::min<uint32_t>(aLength, 4096);
+ ScopedDeleteArray<char> buf(new char[bufSize]);
+
+ uint32_t remaining = aLength;
+ do {
+ // Read data into temporary buffer.
+ uint32_t bytesRead;
+ uint32_t amount = std::min(remaining, bufSize);
+ nsresult rv = Read(buf, amount, &bytesRead);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ MOZ_ASSERT(bytesRead <= amount);
+
+ if (bytesRead == 0) {
+ break;
+ }
+
+ // Copy data into actual buffer.
+ if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
+ return NS_ERROR_FAILURE;
+ }
+ PodCopy(data, buf.get(), bytesRead);
+
+ remaining -= bytesRead;
+ data += bytesRead;
+ } while (remaining > 0);
+
+ return remaining > 0 ? NS_ERROR_FAILURE : NS_OK;
}
NS_IMETHODIMP
More information about the tor-commits
mailing list