--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5978,17 +5978,18 @@ nsContentUtils::CreateArrayBuffer(JSCont
int32_t dataLen = aData.Length();
*aResult = JS_NewArrayBuffer(aCx, dataLen);
if (!*aResult) {
return NS_ERROR_FAILURE;
}
if (dataLen > 0) {
NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
- memcpy(JS_GetArrayBufferData(*aResult), aData.BeginReading(), dataLen);
+ JS::AutoCheckCannotGC nogc;
+ memcpy(JS_GetArrayBufferData(*aResult, nogc), aData.BeginReading(), dataLen);
}
return NS_OK;
}
// Initial implementation: only stores to RAM, not file
// TODO: bug 704447: large file support
nsresult
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -289,18 +289,32 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aS
// Clear out the data if necessary
if (NS_FAILED(aStatus)) {
FreeFileData();
return NS_OK;
}
nsresult rv = NS_OK;
switch (mDataFormat) {
- case FILE_AS_ARRAYBUFFER:
- break; //Already accumulated mResultArrayBuffer
+ case FILE_AS_ARRAYBUFFER: {
+ AutoJSAPI jsapi;
+ if (NS_WARN_IF(!jsapi.Init(mozilla::DOMEventTargetHelper::GetParentObject()))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RootResultArrayBuffer();
+ mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mTotal, mFileData);
+ if (!mResultArrayBuffer) {
+ JS_ClearPendingException(jsapi.cx());
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ } else {
+ mFileData = nullptr; // Transfer ownership
+ }
+ break;
+ }
case FILE_AS_BINARY:
break; //Already accumulated mResult
case FILE_AS_TEXT:
if (!mFileData) {
if (mDataLen) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
@@ -337,45 +351,40 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
mResult.GetMutableData(&buf, oldLen + aCount, fallible_t());
NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
uint32_t bytesRead = 0;
aStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount,
&bytesRead);
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}
- else if (mDataFormat == FILE_AS_ARRAYBUFFER) {
- uint32_t bytesRead = 0;
- aStream->Read((char*) JS_GetArrayBufferData(mResultArrayBuffer) + mDataLen,
- aCount, &bytesRead);
- NS_ASSERTION(bytesRead == aCount, "failed to read data");
- }
else {
//Update memory buffer to reflect the contents of the file
if (mDataLen + aCount > UINT32_MAX) {
// PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
return NS_ERROR_OUT_OF_MEMORY;
}
- mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
- NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
+ if (mDataFormat != FILE_AS_ARRAYBUFFER) {
+ mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
+ NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
+ }
uint32_t bytesRead = 0;
aStream->Read(mFileData + mDataLen, aCount, &bytesRead);
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}
mDataLen += aCount;
return NS_OK;
}
// Helper methods
void
-nsDOMFileReader::ReadFileContent(JSContext* aCx,
- File& aFile,
+nsDOMFileReader::ReadFileContent(File& aFile,
const nsAString &aCharset,
eDataFormat aDataFormat,
ErrorResult& aRv)
{
//Implicit abort to clear any other activity going on
Abort();
mError = nullptr;
SetDOMStringToNull(mResult);
@@ -438,21 +447,20 @@ nsDOMFileReader::ReadFileContent(JSConte
return;
}
//FileReader should be in loading state here
mReadyState = nsIDOMFileReader::LOADING;
DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
if (mDataFormat == FILE_AS_ARRAYBUFFER) {
- RootResultArrayBuffer();
- mResultArrayBuffer = JS_NewArrayBuffer(aCx, mTotal);
- if (!mResultArrayBuffer) {
- NS_WARNING("Failed to create JS array buffer");
- aRv.Throw(NS_ERROR_FAILURE);
+ mFileData = js_pod_malloc<char>(mTotal);
+ if (!mFileData) {
+ NS_WARNING("Preallocation failed for ReadFileData");
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
}
}
nsresult
nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
const nsACString &aCharset,
const char *aFileData,
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -65,27 +65,27 @@ public:
}
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL
static already_AddRefed<nsDOMFileReader>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
{
- ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
+ ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
}
void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
{
- ReadFileContent(nullptr, aBlob, aLabel, FILE_AS_TEXT, aRv);
+ ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
}
void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
{
- ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
+ ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
}
using FileIOObject::Abort;
// Inherited ReadyState().
void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv);
@@ -99,17 +99,17 @@ public:
using FileIOObject::GetOnabort;
using FileIOObject::SetOnabort;
using FileIOObject::GetOnerror;
using FileIOObject::SetOnerror;
IMPL_EVENT_HANDLER(loadend)
void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
{
- ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
+ ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
}
nsresult Init();
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
FileIOObject)
void RootResultArrayBuffer();
@@ -119,17 +119,17 @@ protected:
enum eDataFormat {
FILE_AS_ARRAYBUFFER,
FILE_AS_BINARY,
FILE_AS_TEXT,
FILE_AS_DATAURL
};
- void ReadFileContent(JSContext* aCx, File& aBlob,
+ void ReadFileContent(File& aBlob,
const nsAString &aCharset, eDataFormat aDataFormat,
ErrorResult& aRv);
nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
const char *aFileData, uint32_t aDataLen, nsAString &aResult);
nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
void FreeFileData() {
moz_free(mFileData);
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -110,17 +110,18 @@ AudioBuffer::RestoreJSChannelData(JSCont
// The following code first zeroes the array and then copies our data
// into it. We could avoid this with additional JS APIs to construct
// an array (or ArrayBuffer) containing initial data.
JS::Rooted<JSObject*> array(aJSContext,
JS_NewFloat32Array(aJSContext, mLength));
if (!array) {
return false;
}
- memcpy(JS_GetFloat32ArrayData(array), data, sizeof(float)*mLength);
+ JS::AutoCheckCannotGC nogc;
+ mozilla::PodCopy(JS_GetFloat32ArrayData(array, nogc), data, mLength);
mJSChannels[i] = array;
}
mSharedChannels = nullptr;
}
return true;
}
@@ -141,19 +142,20 @@ AudioBuffer::CopyFromChannel(const Float
}
if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
// The array was probably neutered
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
}
+ JS::AutoCheckCannotGC nogc;
const float* sourceData = mSharedChannels ?
mSharedChannels->GetData(aChannelNumber) :
- JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]);
+ JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc);
PodMove(aDestination.Data(), sourceData + aStartInChannel, length);
}
void
AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
uint32_t aChannelNumber, uint32_t aStartInChannel,
ErrorResult& aRv)
{
@@ -174,26 +176,28 @@ AudioBuffer::CopyToChannel(JSContext* aJ
return;
}
if (!RestoreJSChannelData(aJSContext)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
- PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
+ JS::AutoCheckCannotGC nogc;
+ PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc) + aStartInChannel,
aSource.Data(), length);
}
void
AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
{
MOZ_ASSERT(!GetWrapperPreserveColor() && !mSharedChannels,
"The AudioBuffer object should not have been handed to JS or have C++ callers neuter its typed array");
- PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
+ JS::AutoCheckCannotGC nogc;
+ PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel], nogc), aContents, mLength);
}
void
AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv)
{
if (aChannel >= NumberOfChannels()) {
--- a/content/media/webspeech/synth/nsSpeechTask.cpp
+++ b/content/media/webspeech/synth/nsSpeechTask.cpp
@@ -157,16 +157,30 @@ nsSpeechTask::Setup(nsISpeechTaskCallbac
AudioSegment* segment = new AudioSegment();
mStream->AddTrack(1, aRate, 0, segment);
mStream->AddAudioOutput(this);
mStream->SetAudioOutputVolume(this, mVolume);
return NS_OK;
}
+static nsRefPtr<mozilla::SharedBuffer>
+makeSamples(int16_t* aData, uint32_t aDataLen)
+{
+ nsRefPtr<mozilla::SharedBuffer> samples =
+ SharedBuffer::Create(aDataLen * sizeof(int16_t));
+ int16_t* frames = static_cast<int16_t*>(samples->Data());
+
+ for (uint32_t i = 0; i < aDataLen; i++) {
+ frames[i] = aData[i];
+ }
+
+ return samples;
+}
+
NS_IMETHODIMP
nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks,
JSContext* aCx)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
@@ -189,18 +203,23 @@ nsSpeechTask::SendAudio(JS::Handle<JS::V
} else if (JS_IsArrayObject(aCx, darray)) {
tsrc = JS_NewInt16ArrayFromArray(aCx, darray);
}
if (!tsrc) {
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
}
- SendAudioImpl(JS_GetInt16ArrayData(tsrc),
- JS_GetTypedArrayLength(tsrc));
+ uint32_t dataLen = JS_GetTypedArrayLength(tsrc);
+ nsRefPtr<mozilla::SharedBuffer> samples;
+ {
+ JS::AutoCheckCannotGC nogc;
+ samples = makeSamples(JS_GetInt16ArrayData(tsrc, nogc), dataLen);
+ }
+ SendAudioImpl(samples, dataLen);
return NS_OK;
}
NS_IMETHODIMP
nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
@@ -209,41 +228,34 @@ nsSpeechTask::SendAudioNative(int16_t* a
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
if (mIndirectAudio) {
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
return NS_ERROR_FAILURE;
}
- SendAudioImpl(aData, aDataLen);
+ nsRefPtr<mozilla::SharedBuffer> samples = makeSamples(aData, aDataLen);
+ SendAudioImpl(samples, aDataLen);
return NS_OK;
}
void
-nsSpeechTask::SendAudioImpl(int16_t* aData, uint32_t aDataLen)
+nsSpeechTask::SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen)
{
if (aDataLen == 0) {
mStream->EndAllTrackAndFinish();
return;
}
- nsRefPtr<mozilla::SharedBuffer> samples =
- SharedBuffer::Create(aDataLen * sizeof(int16_t));
- int16_t* frames = static_cast<int16_t*>(samples->Data());
-
- for (uint32_t i = 0; i < aDataLen; i++) {
- frames[i] = aData[i];
- }
-
AudioSegment segment;
nsAutoTArray<const int16_t*, 1> channelData;
- channelData.AppendElement(frames);
- segment.AppendFrames(samples.forget(), channelData, aDataLen);
+ channelData.AppendElement(static_cast<int16_t*>(aSamples->Data()));
+ segment.AppendFrames(aSamples.forget(), channelData, aDataLen);
mStream->AppendToTrack(1, &segment);
mStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
}
NS_IMETHODIMP
nsSpeechTask::DispatchStart()
{
if (!mIndirectAudio) {
--- a/content/media/webspeech/synth/nsSpeechTask.h
+++ b/content/media/webspeech/synth/nsSpeechTask.h
@@ -69,17 +69,17 @@ protected:
float mVolume;
nsString mText;
private:
void End();
- void SendAudioImpl(int16_t* aData, uint32_t aDataLen);
+ void SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen);
nsRefPtr<SourceMediaStream> mStream;
nsCOMPtr<nsISpeechTaskCallback> mCallback;
uint32_t mChannels;
nsRefPtr<SpeechSynthesis> mSpeechSynthesis;
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -134,17 +134,17 @@ public:
private:
TypedArray_base(const TypedArray_base&) MOZ_DELETE;
};
template<typename T,
JSObject* UnwrapArray(JSObject*),
- T* GetData(JSObject*),
+ T* GetData(JSObject*, const JS::AutoCheckCannotGC&),
void GetLengthAndData(JSObject*, uint32_t*, T**),
JSObject* CreateNew(JSContext*, uint32_t)>
struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
private:
typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
public:
TypedArray()
@@ -176,17 +176,18 @@ public:
private:
static inline JSObject*
CreateCommon(JSContext* cx, uint32_t length, const T* data) {
JSObject* obj = CreateNew(cx, length);
if (!obj) {
return nullptr;
}
if (data) {
- T* buf = static_cast<T*>(GetData(obj));
+ JS::AutoCheckCannotGC nogc;
+ T* buf = static_cast<T*>(GetData(obj, nogc));
memcpy(buf, data, length*sizeof(T));
}
return obj;
}
TypedArray(const TypedArray&) MOZ_DELETE;
};
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4510,28 +4510,34 @@ CanvasRenderingContext2D::GetImageDataAr
return NS_ERROR_OUT_OF_MEMORY;
}
if (mZero) {
*aRetval = darray;
return NS_OK;
}
- uint8_t* data = JS_GetUint8ClampedArrayData(darray);
-
IntRect dstWriteRect = srcReadRect;
dstWriteRect.MoveBy(-aX, -aY);
- uint8_t* src = data;
- uint32_t srcStride = aWidth * 4;
+ uint8_t* src;
+ uint32_t srcStride;
+
if (readback) {
srcStride = readback->Stride();
src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
}
+ JS::AutoCheckCannotGC nogc;
+ uint8_t* data = JS_GetUint8ClampedArrayData(darray, nogc);
+ if (!readback) {
+ src = data;
+ srcStride = aWidth * 4;
+ }
+
// NOTE! dst is the same as src, and this relies on reading
// from src and advancing that ptr before writing to dst.
// NOTE! I'm not sure that it is, I think this comment might have been
// inherited from Thebes canvas and is no longer true
uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
if (mOpaque) {
for (int32_t j = 0; j < dstWriteRect.height; ++j) {
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -338,17 +338,18 @@ void
FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval)
{
uint64_t group;
if (!IFMRadioService::Singleton()->GetRdsgroup(group)) {
return;
}
JSObject *rdsgroup = Uint16Array::Create(cx, this, 4);
- uint16_t *data = JS_GetUint16ArrayData(rdsgroup);
+ JS::AutoCheckCannotGC nogc;
+ uint16_t *data = JS_GetUint16ArrayData(rdsgroup, nogc);
data[3] = group & 0xFFFF;
group >>= 16;
data[2] = group & 0xFFFF;
group >>= 16;
data[1] = group & 0xFFFF;
group >>= 16;
data[0] = group & 0xFFFF;
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -1,15 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <algorithm>
#include "TCPSocketChild.h"
#include "mozilla/unused.h"
+#include "mozilla/UniquePtr.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
#include "nsIDOMTCPSocket.h"
#include "nsJSUtils.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "jsfriendapi.h"
@@ -22,24 +23,27 @@ namespace IPC {
bool
DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
const InfallibleTArray<uint8_t>& aBuffer,
JS::MutableHandle<JS::Value> aVal)
{
mozilla::AutoSafeJSContext cx;
JSAutoCompartment ac(cx, aObj);
- JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
+ mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
+ if (!data)
+ return false;
+ memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
+
+ JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
if (!obj)
- return false;
- uint8_t* data = JS_GetArrayBufferData(obj);
- if (!data)
- return false;
- memcpy(data, aBuffer.Elements(), aBuffer.Length());
- aVal.set(OBJECT_TO_JSVAL(obj));
+ return false;
+ data.release();
+
+ aVal.setObject(*obj);
return true;
}
} // namespace IPC
namespace mozilla {
namespace dom {
@@ -219,23 +223,26 @@ TCPSocketChild::SendSend(JS::Handle<JS::
SendData(str, aTrackingNumber);
} else {
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
uint32_t buflen = JS_GetArrayBufferByteLength(obj);
aByteOffset = std::min(buflen, aByteOffset);
uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
- uint8_t* data = JS_GetArrayBufferData(obj);
- if (!data) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
FallibleTArray<uint8_t> fallibleArr;
- if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
- return NS_ERROR_OUT_OF_MEMORY;
+ {
+ JS::AutoCheckCannotGC nogc;
+ uint8_t* data = JS_GetArrayBufferData(obj, nogc);
+ if (!data) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
SendData(arr, aTrackingNumber);
}
return NS_OK;
}
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -280,27 +280,37 @@ TCPSocketParent::SendEvent(const nsAStri
data = SendableData(str);
} else if (aDataVal.isUndefined() || aDataVal.isNull()) {
data = mozilla::void_t();
} else if (aDataVal.isObject()) {
JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
if (JS_IsArrayBufferObject(obj)) {
- uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
- uint8_t* buffer = JS_GetArrayBufferData(obj);
- if (!buffer) {
- FireInteralError(this, __LINE__);
- return NS_ERROR_OUT_OF_MEMORY;
+ FallibleTArray<uint8_t> fallibleArr;
+ uint32_t errLine = 0;
+ do {
+ JS::AutoCheckCannotGC nogc;
+ uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
+ uint8_t* buffer = JS_GetArrayBufferData(obj, nogc);
+ if (!buffer) {
+ errLine = __LINE__;
+ break;
+ }
+ if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
+ errLine = __LINE__;
+ break;
+ }
+ } while (false);
+
+ if (errLine) {
+ FireInteralError(this, errLine);
+ return NS_ERROR_OUT_OF_MEMORY;
}
- FallibleTArray<uint8_t> fallibleArr;
- if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
- FireInteralError(this, __LINE__);
- return NS_ERROR_OUT_OF_MEMORY;
- }
+
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
data = SendableData(arr);
} else {
nsAutoJSString name;
JS::Rooted<JS::Value> val(aCx);
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -56,47 +56,45 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
{
uint64_t blobSize;
nsresult rv = aBlob.GetSize(&blobSize);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
}
- JS::Rooted<JSObject*> jsArrayBuffer(aCx, JS_NewArrayBuffer(aCx, blobSize));
- if (!jsArrayBuffer) {
- // XXXkhuey we need a way to indicate to the bindings that the call failed
- // but there's already a pending exception that we should not clobber.
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
- uint8_t* arrayBuffer = JS_GetStableArrayBufferData(aCx, jsArrayBuffer);
- if (!arrayBuffer) {
+ UniquePtr<char[], JS::FreePolicy> bufferData(js_pod_malloc<char>(blobSize));
+ if (!bufferData) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
nsCOMPtr<nsIInputStream> stream;
rv = aBlob.GetInternalStream(getter_AddRefs(stream));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
}
uint32_t numRead;
- rv = stream->Read((char*)arrayBuffer, bufferLength, &numRead);
+ rv = stream->Read(bufferData.get(), blobSize, &numRead);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
}
- NS_ASSERTION(numRead == bufferLength, "failed to read data");
+ NS_ASSERTION(numRead == blobSize, "failed to read data");
- aRetval.set(jsArrayBuffer);
+ JSObject* arrayBuffer = JS_NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
+ if (!arrayBuffer) {
+ aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ bufferData.release();
+
+ aRetval.set(arrayBuffer);
}
void
FileReaderSync::ReadAsBinaryString(File& aBlob,
nsAString& aResult,
ErrorResult& aRv)
{
nsCOMPtr<nsIInputStream> stream;
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -87,51 +87,55 @@ PostToRIL(JSContext *aCx,
if (args.length() != 2) {
JS_ReportError(aCx, "Expecting two arguments with the RIL message");
return false;
}
int clientId = args[0].toInt32();
JS::Value v = args[1];
- JSAutoByteString abs;
- void *data;
- size_t size;
+ UnixSocketRawData* raw = nullptr;
+
if (v.isString()) {
+ JSAutoByteString abs;
JS::Rooted<JSString*> str(aCx, v.toString());
if (!abs.encodeUtf8(aCx, str)) {
return false;
}
- data = abs.ptr();
- size = abs.length();
+ raw = new UnixSocketRawData(abs.ptr(), abs.length());
} else if (!v.isPrimitive()) {
JSObject *obj = v.toObjectOrNull();
if (!JS_IsTypedArrayObject(obj)) {
JS_ReportError(aCx, "Object passed in wasn't a typed array");
return false;
}
uint32_t type = JS_GetArrayBufferViewType(obj);
if (type != js::Scalar::Int8 &&
type != js::Scalar::Uint8 &&
type != js::Scalar::Uint8Clamped) {
JS_ReportError(aCx, "Typed array data is not octets");
return false;
}
- size = JS_GetTypedArrayByteLength(obj);
- data = JS_GetArrayBufferViewData(obj);
+ JS::AutoCheckCannotGC nogc;
+ size_t size = JS_GetTypedArrayByteLength(obj);
+ void *data = JS_GetArrayBufferViewData(obj, nogc);
+ raw = new UnixSocketRawData(data, size);
} else {
JS_ReportError(aCx,
"Incorrect argument. Expecting a string or a typed array");
return false;
}
- UnixSocketRawData* raw = new UnixSocketRawData(data, size);
+ if (!raw) {
+ JS_ReportError(aCx, "Unable to post to RIL");
+ return false;
+ }
nsRefPtr<SendRilSocketDataTask> task =
new SendRilSocketDataTask(clientId, raw);
NS_DispatchToMainThread(task);
return true;
}
bool
@@ -184,18 +188,21 @@ DispatchRILEvent::RunTask(JSContext *aCx
{
JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Rooted<JSObject*> array(aCx,
JS_NewUint8Array(aCx, mMessage->GetSize()));
if (!array) {
return false;
}
- memcpy(JS_GetArrayBufferViewData(array),
- mMessage->GetData(), mMessage->GetSize());
+ {
+ JS::AutoCheckCannotGC nogc;
+ memcpy(JS_GetArrayBufferViewData(array, nogc),
+ mMessage->GetData(), mMessage->GetSize());
+ }
JS::AutoValueArray<2> args(aCx);
args[0].setNumber((uint32_t)mClientId);
args[1].setObject(*array);
JS::Rooted<JS::Value> rval(aCx);
return JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
}
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2456,33 +2456,44 @@ ImplicitConvert(JSContext* cx,
(*char16Buffer)[sourceLength] = 0;
break;
}
default:
return TypeError(cx, "string pointer", val);
}
break;
} else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
- // Convert ArrayBuffer to pointer without any copy.
- // Just as with C arrays, we make no effort to
- // keep the ArrayBuffer alive.
- void* p = JS_GetStableArrayBufferData(cx, valObj);
- if (!p)
- return false;
- *static_cast<void**>(buffer) = p;
+ // Convert ArrayBuffer to pointer without any copy. Just as with C
+ // arrays, we make no effort to keep the ArrayBuffer alive. This
+ // functionality will be removed for all but arguments in bug 1080262.
+ void* ptr;
+ {
+ JS::AutoCheckCannotGC nogc;
+ ptr = JS_GetArrayBufferData(valObj, nogc);
+ }
+ if (!ptr) {
+ return TypeError(cx, "arraybuffer pointer", val);
+ }
+ *static_cast<void**>(buffer) = ptr;
break;
} if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
+ // Same as ArrayBuffer, above, though note that this will take the offset
+ // of the view into account.
if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
return TypeError(cx, "typed array with the appropriate type", val);
}
-
- // Convert TypedArray to pointer without any copy.
- // Just as with C arrays, we make no effort to
- // keep the TypedArray alive.
- *static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
+ void* ptr;
+ {
+ JS::AutoCheckCannotGC nogc;
+ ptr = JS_GetArrayBufferViewData(valObj, nogc);
+ }
+ if (!ptr) {
+ return TypeError(cx, "typed array pointer", val);
+ }
+ *static_cast<void**>(buffer) = ptr;
break;
}
return TypeError(cx, "pointer", val);
}
case TYPE_array: {
RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
size_t targetLength = ArrayType::GetLength(targetType);
@@ -2578,33 +2589,35 @@ ImplicitConvert(JSContext* cx,
// copy the array.
uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
size_t elementSize = CType::GetSize(baseType);
size_t arraySize = elementSize * targetLength;
if (arraySize != size_t(sourceLength)) {
JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
return false;
}
- memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
+ JS::AutoCheckCannotGC nogc;
+ memcpy(buffer, JS_GetArrayBufferData(valObj, nogc), sourceLength);
break;
} else if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
// Check that array is consistent with type, then
// copy the array.
if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
return TypeError(cx, "typed array with the appropriate type", val);
}
uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
size_t elementSize = CType::GetSize(baseType);
size_t arraySize = elementSize * targetLength;
if (arraySize != size_t(sourceLength)) {
JS_ReportError(cx, "typed array length does not match source TypedArray length");
return false;
}
- memcpy(buffer, JS_GetArrayBufferViewData(valObj), sourceLength);
+ JS::AutoCheckCannotGC nogc;
+ memcpy(buffer, JS_GetArrayBufferViewData(valObj, nogc), sourceLength);
break;
} else {
// Don't implicitly convert to string. Users can implicitly convert
// with `String(x)` or `""+x`.
return TypeError(cx, "array", val);
}
break;
}
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -72,16 +72,17 @@ var ignoreCallees = {
"js::Class.trace" : true,
"js::Class.finalize" : true,
"JSRuntime.destroyPrincipals" : true,
"icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
"mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
"PLDHashTableOps.hashKey" : true,
"z_stream_s.zfree" : true,
+ "GrGLInterface.fCallback" : true,
};
function fieldCallCannotGC(csu, fullfield)
{
if (csu in ignoreClasses)
return true;
if (fullfield in ignoreCallees)
return true;
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -39,26 +39,28 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
CHECK(JS_IsArrayBufferObject(obj));
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), size);
JS_GetProperty(cx, obj, "byteLength", &v);
CHECK_SAME(v, INT_TO_JSVAL(size));
JS_GetProperty(cx, view, "byteLength", &v);
CHECK_SAME(v, INT_TO_JSVAL(size));
// Modifying the underlying data should update the value returned through the view
- uint8_t *data = JS_GetStableArrayBufferData(cx, obj);
- CHECK(data != nullptr);
- *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
+ {
+ JS::AutoCheckCannotGC nogc;
+ uint8_t *data = JS_GetArrayBufferData(obj, nogc);
+ CHECK(data != nullptr);
+ *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
+ }
CHECK(JS_GetElement(cx, view, 0, &v));
CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
// Steal the contents
void *contents = JS_StealArrayBufferContents(cx, obj);
CHECK(contents != nullptr);
- CHECK(data != nullptr);
// Check that the original ArrayBuffer is neutered
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
CHECK_SAME(v, INT_TO_JSVAL(0));
CHECK(JS_GetProperty(cx, view, "byteLength", &v));
CHECK_SAME(v, INT_TO_JSVAL(0));
CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
@@ -68,25 +70,31 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
v = JSVAL_VOID;
JS_GetElement(cx, obj, 0, &v);
CHECK_SAME(v, JSVAL_VOID);
// Transfer to a new ArrayBuffer
JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
CHECK(JS_IsArrayBufferObject(dst));
- data = JS_GetStableArrayBufferData(cx, obj);
+ {
+ JS::AutoCheckCannotGC nogc;
+ (void) JS_GetArrayBufferData(obj, nogc);
+ }
JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
CHECK(dstview != nullptr);
CHECK_EQUAL(JS_GetArrayBufferByteLength(dst), size);
- data = JS_GetStableArrayBufferData(cx, dst);
- CHECK(data != nullptr);
- CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
+ {
+ JS::AutoCheckCannotGC nogc;
+ uint8_t *data = JS_GetArrayBufferData(dst, nogc);
+ CHECK(data != nullptr);
+ CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
+ }
CHECK(JS_GetElement(cx, dstview, 0, &v));
CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
}
return true;
}
END_TEST(testArrayBuffer_bug720949_steal)
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -69,24 +69,26 @@ JSObject *CreateNewObject(const int offs
JS_ReleaseMappedArrayBufferContents(ptr, length);
return nullptr;
}
return obj;
}
bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const bool mapped)
{
+ JS::AutoCheckCannotGC nogc;
+
CHECK(obj);
CHECK(JS_IsArrayBufferObject(obj));
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
if (mapped)
CHECK(JS_IsMappedArrayBufferObject(obj));
else
CHECK(!JS_IsMappedArrayBufferObject(obj));
- const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj));
+ const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj, nogc));
CHECK(data);
CHECK(memcmp(data, test_data + offset, length) == 0);
return true;
}
bool TestCreateObject(uint32_t offset, uint32_t length)
{
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -31,18 +31,21 @@ BEGIN_TEST(testTypedArrays)
CHECK(JS_IsArrayBufferObject(buffer));
RootedObject proto(cx);
JS_GetPrototype(cx, buffer, &proto);
CHECK(!JS_IsArrayBufferObject(proto));
RootedObject dummy(cx, JS_GetParent(proto));
CHECK(!JS_IsArrayBufferObject(dummy));
- CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
- memset(JS_GetStableArrayBufferData(cx, buffer), 1, nbytes);
+ {
+ JS::AutoCheckCannotGC nogc;
+ CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
+ memset(JS_GetArrayBufferData(buffer, nogc), 1, nbytes);
+ }
ok = ok &&
TestArrayFromBuffer<JS_NewInt8ArrayWithBuffer, JS_NewInt8ArrayFromArray, int8_t, JS_GetInt8ArrayData>(cx) &&
TestArrayFromBuffer<JS_NewUint8ArrayWithBuffer, JS_NewUint8ArrayFromArray, uint8_t, JS_GetUint8ArrayData>(cx) &&
TestArrayFromBuffer<JS_NewUint8ClampedArrayWithBuffer, JS_NewUint8ClampedArrayFromArray, uint8_t, JS_GetUint8ClampedArrayData>(cx) &&
TestArrayFromBuffer<JS_NewInt16ArrayWithBuffer, JS_NewInt16ArrayFromArray, int16_t, JS_GetInt16ArrayData>(cx) &&
TestArrayFromBuffer<JS_NewUint16ArrayWithBuffer, JS_NewUint16ArrayFromArray, uint16_t, JS_GetUint16ArrayData>(cx) &&
TestArrayFromBuffer<JS_NewInt32ArrayWithBuffer, JS_NewInt32ArrayFromArray, int32_t, JS_GetInt32ArrayData>(cx) &&
@@ -50,17 +53,17 @@ BEGIN_TEST(testTypedArrays)
TestArrayFromBuffer<JS_NewFloat32ArrayWithBuffer, JS_NewFloat32ArrayFromArray, float, JS_GetFloat32ArrayData>(cx) &&
TestArrayFromBuffer<JS_NewFloat64ArrayWithBuffer, JS_NewFloat64ArrayFromArray, double, JS_GetFloat64ArrayData>(cx);
return ok;
}
template<JSObject *Create(JSContext *, uint32_t),
typename Element,
- Element *GetData(JSObject *)>
+ Element *GetData(JSObject *, const JS::AutoCheckCannotGC&)>
bool
TestPlainTypedArray(JSContext *cx)
{
{
RootedObject notArray(cx, Create(cx, UINT32_MAX));
CHECK(!notArray);
}
@@ -71,58 +74,64 @@ TestPlainTypedArray(JSContext *cx)
CHECK(!JS_IsTypedArrayObject(proto));
RootedObject dummy(cx, JS_GetParent(proto));
CHECK(!JS_IsTypedArrayObject(dummy));
CHECK_EQUAL(JS_GetTypedArrayLength(array), 7u);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7);
- Element *data;
- CHECK(data = GetData(array));
- *data = 13;
+ {
+ JS::AutoCheckCannotGC nogc;
+ Element *data;
+ CHECK(data = GetData(array, nogc));
+ *data = 13;
+ }
RootedValue v(cx);
CHECK(JS_GetElement(cx, array, 0, &v));
CHECK_SAME(v, INT_TO_JSVAL(13));
return true;
}
template<JSObject *CreateWithBuffer(JSContext *, JS::HandleObject, uint32_t, int32_t),
JSObject *CreateFromArray(JSContext *, JS::HandleObject),
typename Element,
- Element *GetData(JSObject *)>
+ Element *GetData(JSObject *, const JS::AutoCheckCannotGC&)>
bool
TestArrayFromBuffer(JSContext *cx)
{
size_t elts = 8;
size_t nbytes = elts * sizeof(Element);
RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
- uint8_t *bufdata;
- CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
- memset(bufdata, 1, nbytes);
+ {
+ JS::AutoCheckCannotGC nogc;
+ memset(JS_GetArrayBufferData(buffer, nogc), 1, nbytes);
+ }
{
RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1));
CHECK(!notArray);
}
RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1));
CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer);
- Element *data;
- CHECK(data = GetData(array));
- CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
- CHECK_EQUAL((void*) data, (void*) bufdata);
+ {
+ JS::AutoCheckCannotGC nogc;
+ Element *data;
+ CHECK(data = GetData(array, nogc));
+ CHECK_EQUAL((void*) data, (void*) JS_GetArrayBufferData(buffer, nogc));
- CHECK_EQUAL(*bufdata, 1u);
- CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
+ CHECK_EQUAL(*reinterpret_cast<uint8_t*>(JS_GetArrayBufferData(buffer, nogc)), 1u);
+ CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
+ }
RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2));
CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0u);
CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray), nbytes / 2);
RootedObject ofsArray(cx, CreateWithBuffer(cx, buffer, nbytes / 2, -1));
CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray), elts / 2);
@@ -132,33 +141,48 @@ TestArrayFromBuffer(JSContext *cx)
// Make sure all 3 views reflect the same buffer at the expected locations
JS::RootedValue v(cx, INT_TO_JSVAL(39));
JS_SetElement(cx, array, 0, v);
JS::RootedValue v2(cx);
CHECK(JS_GetElement(cx, array, 0, &v2));
CHECK_SAME(v, v2);
CHECK(JS_GetElement(cx, shortArray, 0, &v2));
CHECK_SAME(v, v2);
- CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[0]));
+ {
+ JS::AutoCheckCannotGC nogc;
+ Element *data;
+ CHECK(data = GetData(array, nogc));
+ CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[0]));
+ }
v = INT_TO_JSVAL(40);
JS_SetElement(cx, array, elts / 2, v);
CHECK(JS_GetElement(cx, array, elts / 2, &v2));
CHECK_SAME(v, v2);
CHECK(JS_GetElement(cx, ofsArray, 0, &v2));
CHECK_SAME(v, v2);
- CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts / 2]));
+ {
+ JS::AutoCheckCannotGC nogc;
+ Element *data;
+ CHECK(data = GetData(array, nogc));
+ CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts / 2]));
+ }
v = INT_TO_JSVAL(41);
JS_SetElement(cx, array, elts - 1, v);
CHECK(JS_GetElement(cx, array, elts - 1, &v2));
CHECK_SAME(v, v2);
CHECK(JS_GetElement(cx, ofsArray, elts / 2 - 1, &v2));
CHECK_SAME(v, v2);
- CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts - 1]));
+ {
+ JS::AutoCheckCannotGC nogc;
+ Element *data;
+ CHECK(data = GetData(array, nogc));
+ CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts - 1]));
+ }
JS::RootedObject copy(cx, CreateFromArray(cx, array));
CHECK(JS_GetElement(cx, array, 0, &v));
CHECK(JS_GetElement(cx, copy, 0, &v2));
CHECK_SAME(v, v2);
/* The copy should not see changes in the original */
v2 = INT_TO_JSVAL(42);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1947,49 +1947,42 @@ JS_GetArrayBufferViewByteLength(JSObject
* care not to hold on across anything that could GC.
*
* |obj| must have passed a JS_Is*Array test, or somehow be known that it would
* pass such a test: it is a typed array or a wrapper of a typed array, and the
* unwrapping will succeed.
*/
extern JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj);
+JS_GetArrayBufferData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(int8_t *)
-JS_GetInt8ArrayData(JSObject *obj);
+JS_GetInt8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(uint8_t *)
-JS_GetUint8ArrayData(JSObject *obj);
+JS_GetUint8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(uint8_t *)
-JS_GetUint8ClampedArrayData(JSObject *obj);
+JS_GetUint8ClampedArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(int16_t *)
-JS_GetInt16ArrayData(JSObject *obj);
+JS_GetInt16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(uint16_t *)
-JS_GetUint16ArrayData(JSObject *obj);
+JS_GetUint16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(int32_t *)
-JS_GetInt32ArrayData(JSObject *obj);
+JS_GetInt32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(uint32_t *)
-JS_GetUint32ArrayData(JSObject *obj);
+JS_GetUint32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(float *)
-JS_GetFloat32ArrayData(JSObject *obj);
+JS_GetFloat32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
extern JS_FRIEND_API(double *)
-JS_GetFloat64ArrayData(JSObject *obj);
-
-/*
- * Stable versions of the above functions where the buffer remains valid as long
- * as the object is live.
- */
-extern JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, JS::HandleObject obj);
+JS_GetFloat64ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
/*
* Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
* versions when possible.
*/
extern JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj);
+JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&);
/*
* Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
* neutered, this will still return the neutered buffer. |obj| must be an
* object that would return true for JS_IsArrayBufferViewObject().
*/
extern JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSContext *cx, JS::HandleObject obj);
@@ -2052,17 +2045,17 @@ JS_GetDataViewByteLength(JSObject *obj);
* Return a pointer to the beginning of the data referenced by a DataView.
*
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
* it would pass such a test: it is a data view or a wrapper of a data view,
* and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be
* unable to assert when unwrapping should be disallowed.
*/
JS_FRIEND_API(void *)
-JS_GetDataViewData(JSObject *obj);
+JS_GetDataViewData(JSObject *obj, const JS::AutoCheckCannotGC&);
namespace js {
/*
* Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the
* property |id|, using the callable object |callable| as the function to be
* called for notifications.
*
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1061,21 +1061,21 @@ CacheEntry_getBytecode(HandleObject cach
*length = arrayBuffer->byteLength();
return arrayBuffer->dataPointer();
}
static bool
CacheEntry_setBytecode(JSContext *cx, HandleObject cache, uint8_t *buffer, uint32_t length)
{
MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
+
ArrayBufferObject::BufferContents contents =
ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(buffer);
Rooted<ArrayBufferObject*> arrayBuffer(cx, ArrayBufferObject::create(cx, length, contents));
-
- if (!arrayBuffer || !ArrayBufferObject::ensureNonInline(cx, arrayBuffer))
+ if (!arrayBuffer)
return false;
SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer));
return true;
}
class AutoSaveFrameChain
{
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -372,18 +372,23 @@ ArrayBufferObject::changeContents(JSCont
}
/* static */ bool
ArrayBufferObject::prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer)
{
if (buffer->isAsmJSArrayBuffer())
return true;
- if (!ensureNonInline(cx, buffer))
- return false;
+ if (!buffer->ownsData()) {
+ BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
+ if (!contents)
+ return false;
+ memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
+ buffer->changeContents(cx, contents);
+ }
buffer->setIsAsmJSArrayBuffer();
return true;
}
void
ArrayBufferObject::releaseAsmJSArrayNoSignals(FreeOp *fop)
{
@@ -692,30 +697,16 @@ ArrayBufferObject::createDataViewForThis
bool
ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
}
-/* static */ bool
-ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
- if (!buffer->ownsData()) {
- BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
- if (!contents)
- return false;
- memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
- buffer->changeContents(cx, contents);
- }
-
- return true;
-}
-
/* static */ ArrayBufferObject::BufferContents
ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer,
bool hasStealableContents)
{
MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
if (!buffer->canNeuter(cx)) {
js_ReportOverRecursed(cx);
@@ -1052,38 +1043,24 @@ js::UnwrapArrayBufferView(JSObject *obj)
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj)
{
obj = CheckedUnwrap(obj);
return obj ? AsArrayBuffer(obj).byteLength() : 0;
}
JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj)
+JS_GetArrayBufferData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
return AsArrayBuffer(obj).dataPointer();
}
-JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, HandleObject objArg)
-{
- JSObject *obj = CheckedUnwrap(objArg);
- if (!obj)
- return nullptr;
-
- Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(obj));
- if (!ArrayBufferObject::ensureNonInline(cx, buffer))
- return nullptr;
-
- 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;
}
@@ -1214,17 +1191,17 @@ JS_IsMappedArrayBufferObject(JSObject *o
return false;
return obj->is<ArrayBufferObject>()
? obj->as<ArrayBufferObject>().isMappedArrayBuffer()
: false;
}
JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj)
+JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
: obj->as<TypedArrayObject>().viewData();
}
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2146,105 +2146,105 @@ JS_GetArrayBufferViewType(JSObject *obj)
if (obj->is<TypedArrayObject>())
return obj->as<TypedArrayObject>().type();
else if (obj->is<DataViewObject>())
return Scalar::TypeMax;
MOZ_CRASH("invalid ArrayBufferView type");
}
JS_FRIEND_API(int8_t *)
-JS_GetInt8ArrayData(JSObject *obj)
+JS_GetInt8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int8);
return static_cast<int8_t *>(tarr->viewData());
}
JS_FRIEND_API(uint8_t *)
-JS_GetUint8ArrayData(JSObject *obj)
+JS_GetUint8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8);
return static_cast<uint8_t *>(tarr->viewData());
}
JS_FRIEND_API(uint8_t *)
-JS_GetUint8ClampedArrayData(JSObject *obj)
+JS_GetUint8ClampedArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8Clamped);
return static_cast<uint8_t *>(tarr->viewData());
}
JS_FRIEND_API(int16_t *)
-JS_GetInt16ArrayData(JSObject *obj)
+JS_GetInt16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int16);
return static_cast<int16_t *>(tarr->viewData());
}
JS_FRIEND_API(uint16_t *)
-JS_GetUint16ArrayData(JSObject *obj)
+JS_GetUint16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint16);
return static_cast<uint16_t *>(tarr->viewData());
}
JS_FRIEND_API(int32_t *)
-JS_GetInt32ArrayData(JSObject *obj)
+JS_GetInt32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int32);
return static_cast<int32_t *>(tarr->viewData());
}
JS_FRIEND_API(uint32_t *)
-JS_GetUint32ArrayData(JSObject *obj)
+JS_GetUint32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint32);
return static_cast<uint32_t *>(tarr->viewData());
}
JS_FRIEND_API(float *)
-JS_GetFloat32ArrayData(JSObject *obj)
+JS_GetFloat32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float32);
return static_cast<float *>(tarr->viewData());
}
JS_FRIEND_API(double *)
-JS_GetFloat64ArrayData(JSObject *obj)
+JS_GetFloat64ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float64);
return static_cast<double *>(tarr->viewData());
}
@@ -2261,17 +2261,17 @@ JS_GetDataViewByteOffset(JSObject *obj)
{
obj = CheckedUnwrap(obj);
if (!obj)
return 0;
return obj->as<DataViewObject>().byteOffset();
}
JS_FRIEND_API(void *)
-JS_GetDataViewData(JSObject *obj)
+JS_GetDataViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
return obj->as<DataViewObject>().dataPointer();
}
JS_FRIEND_API(uint32_t)
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1361,17 +1361,18 @@ CheckTargetAndPopulate(const nsXPTType&
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_GetArrayBufferViewData(tArr), byteSize);
+ JS::AutoCheckCannotGC nogc;
+ memcpy(*output, JS_GetArrayBufferViewData(tArr, nogc), 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
--- a/netwerk/base/src/ArrayBufferInputStream.cpp
+++ b/netwerk/base/src/ArrayBufferInputStream.cpp
@@ -7,18 +7,17 @@
#include "ArrayBufferInputStream.h"
#include "nsStreamUtils.h"
#include "jsapi.h"
#include "jsfriendapi.h"
NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream);
ArrayBufferInputStream::ArrayBufferInputStream()
-: mBuffer(nullptr)
-, mBufferLength(0)
+: mBufferLength(0)
, mOffset(0)
, mPos(0)
, mClosed(false)
{
}
NS_IMETHODIMP
ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
@@ -29,42 +28,39 @@ ArrayBufferInputStream::SetData(JS::Hand
if (!aBuffer.isObject()) {
return NS_ERROR_FAILURE;
}
JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject());
if (!JS_IsArrayBufferObject(arrayBuffer)) {
return NS_ERROR_FAILURE;
}
- mArrayBuffer.emplace(aCx, aBuffer);
+ mArrayBuffer.emplace(aCx, arrayBuffer);
uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer);
mOffset = std::min(buflen, aByteOffset);
mBufferLength = std::min(buflen - mOffset, aLength);
- mBuffer = JS_GetStableArrayBufferData(aCx, arrayBuffer);
- if (!mBuffer) {
- return NS_ERROR_FAILURE;
- }
return NS_OK;
}
NS_IMETHODIMP
ArrayBufferInputStream::Close()
{
mClosed = true;
return NS_OK;
}
NS_IMETHODIMP
ArrayBufferInputStream::Available(uint64_t* aCount)
{
if (mClosed) {
return NS_BASE_STREAM_CLOSED;
}
- *aCount = mBufferLength - mPos;
+ uint32_t buflen = JS_GetArrayBufferByteLength(mArrayBuffer->get());
+ *aCount = buflen ? buflen - mPos : 0;
return NS_OK;
}
NS_IMETHODIMP
ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
{
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
}
@@ -75,42 +71,56 @@ ArrayBufferInputStream::ReadSegments(nsW
{
NS_ASSERTION(result, "null ptr");
NS_ASSERTION(mBufferLength >= mPos, "bad stream state");
if (mClosed) {
return NS_BASE_STREAM_CLOSED;
}
- uint32_t remaining = mBufferLength - mPos;
- if (mArrayBuffer) {
- JSObject* buf = &mArrayBuffer->get().toObject();
- uint32_t byteLength = JS_GetArrayBufferByteLength(buf);
- if (byteLength == 0 && remaining != 0) {
+ MOZ_ASSERT(mArrayBuffer || (mPos == mBufferLength), "stream inited incorrectly");
+
+ *result = 0;
+ while (mPos < mBufferLength) {
+ uint32_t remaining = mBufferLength - mPos;
+ MOZ_ASSERT(mArrayBuffer);
+ uint32_t byteLength = JS_GetArrayBufferByteLength(mArrayBuffer->get());
+ if (byteLength == 0) {
mClosed = true;
return NS_BASE_STREAM_CLOSED;
}
- } else {
- MOZ_ASSERT(remaining == 0, "stream inited incorrectly");
- }
- if (!remaining) {
- *result = 0;
- return NS_OK;
- }
+ char buffer[8192];
+ uint32_t count = std::min(std::min(aCount, remaining), uint32_t(mozilla::ArrayLength(buffer)));
+ if (count == 0) {
+ break;
+ }
- if (aCount > remaining) {
- aCount = remaining;
- }
- nsresult rv = writer(this, closure, (char*)(mBuffer + mOffset) + mPos,
- 0, aCount, result);
- if (NS_SUCCEEDED(rv)) {
- NS_ASSERTION(*result <= aCount,
+ // It is just barely possible that writer() will detach the ArrayBuffer's
+ // data, setting its length to zero. Or move the data to a different memory
+ // area. (This would only happen in a subclass that passed something other
+ // than NS_CopySegmentToBuffer as 'writer'). So copy the data out into a
+ // holding area before passing it to writer().
+ {
+ JS::AutoCheckCannotGC nogc;
+ char* src = (char*) JS_GetArrayBufferData(mArrayBuffer->get(), nogc) + mOffset + mPos;
+ memcpy(buffer, src, count);
+ }
+ uint32_t written;
+ nsresult rv = writer(this, closure, buffer, 0, count, &written);
+ if (NS_FAILED(rv)) {
+ // InputStreams do not propagate errors to caller.
+ return NS_OK;
+ }
+
+ NS_ASSERTION(written <= count,
"writer should not write more than we asked it to write");
- mPos += *result;
+ mPos += written;
+ *result += written;
+ aCount -= written;
}
return NS_OK;
}
NS_IMETHODIMP
ArrayBufferInputStream::IsNonBlocking(bool *aNonBlocking)
{
--- a/netwerk/base/src/ArrayBufferInputStream.h
+++ b/netwerk/base/src/ArrayBufferInputStream.h
@@ -23,17 +23,16 @@ class ArrayBufferInputStream : public ns
public:
ArrayBufferInputStream();
NS_DECL_ISUPPORTS
NS_DECL_NSIARRAYBUFFERINPUTSTREAM
NS_DECL_NSIINPUTSTREAM
private:
virtual ~ArrayBufferInputStream() {}
- mozilla::Maybe<JS::PersistentRooted<JS::Value> > mArrayBuffer;
- uint8_t* mBuffer; // start of actual buffer
+ mozilla::Maybe<JS::PersistentRooted<JSObject*> > mArrayBuffer;
uint32_t mBufferLength; // length of slice
uint32_t mOffset; // permanent offset from start of actual buffer
uint32_t mPos; // offset from start of slice
bool mClosed;
};
#endif // ArrayBufferInputStream_h
--- a/xpcom/io/nsBinaryStream.cpp
+++ b/xpcom/io/nsBinaryStream.cpp
@@ -836,51 +836,52 @@ nsBinaryInputStream::ReadArrayBuffer(uin
return NS_ERROR_FAILURE;
}
uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer);
if (bufferLength < aLength) {
return NS_ERROR_FAILURE;
}
- char* data = reinterpret_cast<char*>(JS_GetStableArrayBufferData(aCx, buffer));
- if (!data) {
- return NS_ERROR_FAILURE;
- }
-
uint32_t bufSize = std::min<uint32_t>(aLength, 4096);
UniquePtr<char[]> buf = MakeUnique<char[]>(bufSize);
- uint32_t remaining = aLength;
+ uint32_t pos = 0;
*aReadLength = 0;
do {
// Read data into temporary buffer.
uint32_t bytesRead;
- uint32_t amount = std::min(remaining, bufSize);
+ uint32_t amount = std::min(aLength - pos, bufSize);
nsresult rv = Read(buf.get(), amount, &bytesRead);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(bytesRead <= amount);
if (bytesRead == 0) {
break;
}
// Copy data into actual buffer.
+
+ JS::AutoCheckCannotGC nogc;
if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
return NS_ERROR_FAILURE;
}
+ char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(buffer, nogc));
+ if (!data) {
+ return NS_ERROR_FAILURE;
+ }
+
*aReadLength += bytesRead;
- PodCopy(data, buf.get(), bytesRead);
+ PodCopy(data + pos, buf.get(), bytesRead);
- remaining -= bytesRead;
- data += bytesRead;
- } while (remaining > 0);
+ pos += bytesRead;
+ } while (pos < aLength);
return NS_OK;
}
NS_IMETHODIMP
nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports** aObject)
{
nsCID cid;