mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1061288 - Make it harder for ArrayBuffer data pointers to be held across invalidations. r=smaug,terrence,jdm,roc,khuey
This commit is contained in:
parent
e353972dd5
commit
b41205df20
@ -5983,7 +5983,8 @@ nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
|
||||
|
||||
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;
|
||||
|
@ -294,8 +294,22 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,
|
||||
|
||||
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:
|
||||
@ -342,20 +356,16 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t 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);
|
||||
@ -369,8 +379,7 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
|
||||
// Helper methods
|
||||
|
||||
void
|
||||
nsDOMFileReader::ReadFileContent(JSContext* aCx,
|
||||
File& aFile,
|
||||
nsDOMFileReader::ReadFileContent(File& aFile,
|
||||
const nsAString &aCharset,
|
||||
eDataFormat aDataFormat,
|
||||
ErrorResult& aRv)
|
||||
@ -443,11 +452,10 @@ nsDOMFileReader::ReadFileContent(JSContext* aCx,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,17 +70,17 @@ public:
|
||||
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;
|
||||
@ -104,7 +104,7 @@ public:
|
||||
|
||||
void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
|
||||
{
|
||||
ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
|
||||
ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ protected:
|
||||
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,
|
||||
|
@ -115,7 +115,8 @@ AudioBuffer::RestoreJSChannelData(JSContext* aJSContext)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -146,9 +147,10 @@ AudioBuffer::CopyFromChannel(const Float32Array& aDestination, uint32_t aChannel
|
||||
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);
|
||||
}
|
||||
|
||||
@ -179,7 +181,8 @@ AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
|
||||
return;
|
||||
}
|
||||
|
||||
PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc) + aStartInChannel,
|
||||
aSource.Data(), length);
|
||||
}
|
||||
|
||||
@ -188,7 +191,8 @@ 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
|
||||
|
@ -162,6 +162,20 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
|
||||
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)
|
||||
@ -194,8 +208,13 @@ nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLand
|
||||
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;
|
||||
}
|
||||
@ -214,31 +233,24 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
|
||||
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);
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ protected:
|
||||
private:
|
||||
void End();
|
||||
|
||||
void SendAudioImpl(int16_t* aData, uint32_t aDataLen);
|
||||
void SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen);
|
||||
|
||||
nsRefPtr<SourceMediaStream> mStream;
|
||||
|
||||
|
@ -139,7 +139,7 @@ private:
|
||||
|
||||
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> {
|
||||
@ -181,7 +181,8 @@ private:
|
||||
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;
|
||||
|
@ -4515,18 +4515,24 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
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
|
||||
|
@ -343,7 +343,8 @@ FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval)
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#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"
|
||||
@ -27,14 +28,17 @@ DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
|
||||
mozilla::AutoSafeJSContext cx;
|
||||
JSAutoCompartment ac(cx, aObj);
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
|
||||
if (!obj)
|
||||
return false;
|
||||
uint8_t* data = JS_GetArrayBufferData(obj);
|
||||
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
|
||||
if (!data)
|
||||
return false;
|
||||
memcpy(data, aBuffer.Elements(), aBuffer.Length());
|
||||
aVal.set(OBJECT_TO_JSVAL(obj));
|
||||
return false;
|
||||
memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
|
||||
|
||||
JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
|
||||
if (!obj)
|
||||
return false;
|
||||
data.release();
|
||||
|
||||
aVal.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -224,13 +228,16 @@ TCPSocketChild::SendSend(JS::Handle<JS::Value> aData,
|
||||
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);
|
||||
|
@ -285,17 +285,27 @@ TCPSocketParent::SendEvent(const nsAString& aType, JS::Handle<JS::Value> aDataVa
|
||||
} 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;
|
||||
if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
|
||||
FireInteralError(this, __LINE__);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
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;
|
||||
}
|
||||
|
||||
InfallibleTArray<uint8_t> arr;
|
||||
arr.SwapElements(fallibleArr);
|
||||
data = SendableData(arr);
|
||||
|
@ -61,17 +61,8 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
|
||||
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;
|
||||
}
|
||||
@ -84,14 +75,21 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -92,17 +92,16 @@ PostToRIL(JSContext *aCx,
|
||||
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)) {
|
||||
@ -118,15 +117,20 @@ PostToRIL(JSContext *aCx,
|
||||
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);
|
||||
@ -189,8 +193,11 @@ DispatchRILEvent::RunTask(JSContext *aCx)
|
||||
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);
|
||||
|
@ -2461,23 +2461,34 @@ ImplicitConvert(JSContext* cx,
|
||||
}
|
||||
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);
|
||||
@ -2583,7 +2594,8 @@ ImplicitConvert(JSContext* cx,
|
||||
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
|
||||
@ -2599,7 +2611,8 @@ ImplicitConvert(JSContext* cx,
|
||||
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
|
||||
|
@ -77,6 +77,7 @@ var ignoreCallees = {
|
||||
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
|
||||
"PLDHashTableOps.hashKey" : true,
|
||||
"z_stream_s.zfree" : true,
|
||||
"GrGLInterface.fCallback" : true,
|
||||
};
|
||||
|
||||
function fieldCallCannotGC(csu, fullfield)
|
||||
|
@ -44,16 +44,18 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
|
||||
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);
|
||||
@ -73,15 +75,21 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
|
||||
// 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));
|
||||
}
|
||||
|
@ -74,6 +74,8 @@ JSObject *CreateNewObject(const int offset, const int length)
|
||||
|
||||
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);
|
||||
@ -81,7 +83,7 @@ bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const
|
||||
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);
|
||||
|
||||
|
@ -36,8 +36,11 @@ BEGIN_TEST(testTypedArrays)
|
||||
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) &&
|
||||
@ -55,7 +58,7 @@ BEGIN_TEST(testTypedArrays)
|
||||
|
||||
template<JSObject *Create(JSContext *, uint32_t),
|
||||
typename Element,
|
||||
Element *GetData(JSObject *)>
|
||||
Element *GetData(JSObject *, const JS::AutoCheckCannotGC&)>
|
||||
bool
|
||||
TestPlainTypedArray(JSContext *cx)
|
||||
{
|
||||
@ -76,9 +79,12 @@ TestPlainTypedArray(JSContext *cx)
|
||||
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));
|
||||
@ -89,16 +95,17 @@ TestPlainTypedArray(JSContext *cx)
|
||||
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));
|
||||
@ -111,13 +118,15 @@ TestArrayFromBuffer(JSContext *cx)
|
||||
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);
|
||||
@ -137,7 +146,12 @@ TestArrayFromBuffer(JSContext *cx)
|
||||
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);
|
||||
@ -145,7 +159,12 @@ TestArrayFromBuffer(JSContext *cx)
|
||||
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);
|
||||
@ -153,7 +172,12 @@ TestArrayFromBuffer(JSContext *cx)
|
||||
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));
|
||||
|
@ -1952,39 +1952,32 @@ JS_GetArrayBufferViewByteLength(JSObject *obj);
|
||||
*/
|
||||
|
||||
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
|
||||
@ -2057,7 +2050,7 @@ JS_GetDataViewByteLength(JSObject *obj);
|
||||
* 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 {
|
||||
|
||||
|
@ -1066,11 +1066,11 @@ 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));
|
||||
|
@ -377,8 +377,13 @@ ArrayBufferObject::prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObj
|
||||
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;
|
||||
@ -697,20 +702,6 @@ ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *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)
|
||||
@ -1057,7 +1048,7 @@ JS_GetArrayBufferByteLength(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetArrayBufferData(JSObject *obj)
|
||||
JS_GetArrayBufferData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -1065,20 +1056,6 @@ JS_GetArrayBufferData(JSObject *obj)
|
||||
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)
|
||||
@ -1219,7 +1196,7 @@ JS_IsMappedArrayBufferObject(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
|
@ -2151,7 +2151,7 @@ JS_GetArrayBufferViewType(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int8_t *)
|
||||
JS_GetInt8ArrayData(JSObject *obj)
|
||||
JS_GetInt8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2162,7 +2162,7 @@ JS_GetInt8ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ArrayData(JSObject *obj)
|
||||
JS_GetUint8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2173,7 +2173,7 @@ JS_GetUint8ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj)
|
||||
JS_GetUint8ClampedArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2184,7 +2184,7 @@ JS_GetUint8ClampedArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int16_t *)
|
||||
JS_GetInt16ArrayData(JSObject *obj)
|
||||
JS_GetInt16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2195,7 +2195,7 @@ JS_GetInt16ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint16_t *)
|
||||
JS_GetUint16ArrayData(JSObject *obj)
|
||||
JS_GetUint16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2206,7 +2206,7 @@ JS_GetUint16ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int32_t *)
|
||||
JS_GetInt32ArrayData(JSObject *obj)
|
||||
JS_GetInt32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2217,7 +2217,7 @@ JS_GetInt32ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t *)
|
||||
JS_GetUint32ArrayData(JSObject *obj)
|
||||
JS_GetUint32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2228,7 +2228,7 @@ JS_GetUint32ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(float *)
|
||||
JS_GetFloat32ArrayData(JSObject *obj)
|
||||
JS_GetFloat32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2239,7 +2239,7 @@ JS_GetFloat32ArrayData(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(double *)
|
||||
JS_GetFloat64ArrayData(JSObject *obj)
|
||||
JS_GetFloat64ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
@ -2266,7 +2266,7 @@ JS_GetDataViewByteOffset(JSObject *obj)
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj)
|
||||
JS_GetDataViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
|
@ -1366,7 +1366,8 @@ CheckTargetAndPopulate(const nsXPTType& type,
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*output, JS_GetArrayBufferViewData(tArr), byteSize);
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
memcpy(*output, JS_GetArrayBufferViewData(tArr, nogc), byteSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,7 @@
|
||||
NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream);
|
||||
|
||||
ArrayBufferInputStream::ArrayBufferInputStream()
|
||||
: mBuffer(nullptr)
|
||||
, mBufferLength(0)
|
||||
: mBufferLength(0)
|
||||
, mOffset(0)
|
||||
, mPos(0)
|
||||
, mClosed(false)
|
||||
@ -34,15 +33,11 @@ ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -59,7 +54,8 @@ 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;
|
||||
}
|
||||
|
||||
@ -80,32 +76,46 @@ ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
||||
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;
|
||||
|
@ -28,8 +28,7 @@ public:
|
||||
|
||||
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
|
||||
|
@ -841,20 +841,15 @@ nsBinaryInputStream::ReadArrayBuffer(uint32_t 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;
|
||||
@ -866,16 +861,22 @@ nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength,
|
||||
}
|
||||
|
||||
// Copy data into actual buffer.
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aReadLength += bytesRead;
|
||||
PodCopy(data, buf.get(), bytesRead);
|
||||
char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(buffer, nogc));
|
||||
if (!data) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
remaining -= bytesRead;
|
||||
data += bytesRead;
|
||||
} while (remaining > 0);
|
||||
*aReadLength += bytesRead;
|
||||
PodCopy(data + pos, buf.get(), bytesRead);
|
||||
|
||||
pos += bytesRead;
|
||||
} while (pos < aLength);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user