Backed out 3 changesets (bug 1633598) for build bustages at ArrayBufferObject.cpp on a CLOSED TREE

Backed out changeset 77e7a549cf97 (bug 1633598)
Backed out changeset a662b2c07b3a (bug 1633598)
Backed out changeset 7fe73b300a5e (bug 1633598)
This commit is contained in:
Andreea Pavel 2020-05-07 22:53:26 +03:00
Родитель b632b808c3
Коммит b8809d1e54
8 изменённых файлов: 102 добавлений и 205 удалений

Просмотреть файл

@ -51,6 +51,14 @@ void CopyArrayBufferViewOrArrayBufferData(
aOutData.AppendElements(data.mData, data.mLength);
}
void CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBuffer& aBuffer,
nsTArray<uint8_t>& aOutData) {
JS::AutoCheckCannotGC nogc;
aBuffer.ComputeState();
aOutData.Clear();
aOutData.AppendElements(aBuffer.Data(), aBuffer.Length());
}
bool IsClearkeyKeySystem(const nsAString& aKeySystem) {
return aKeySystem.EqualsLiteral(EME_KEY_SYSTEM_CLEARKEY);
}

Просмотреть файл

@ -47,6 +47,10 @@ void CopyArrayBufferViewOrArrayBufferData(
const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView,
nsTArray<uint8_t>& aOutData);
// Overload for ArrayBuffer
void CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBuffer& aBufferOrView,
nsTArray<uint8_t>& aOutData);
struct ArrayData {
explicit ArrayData(const uint8_t* aData, size_t aLength)
: mData(aData), mLength(aLength) {}

Просмотреть файл

@ -7,7 +7,6 @@
#include "MediaEncryptedEvent.h"
#include "mozilla/dom/MediaEncryptedEventBinding.h"
#include "nsContentUtils.h"
#include "js/ArrayBuffer.h"
#include "jsfriendapi.h"
#include "nsINode.h"
#include "mozilla/dom/MediaKeys.h"
@ -78,9 +77,11 @@ already_AddRefed<MediaEncryptedEvent> MediaEncryptedEvent::Constructor(
e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
e->mInitDataType = aEventInitDict.mInitDataType;
if (!aEventInitDict.mInitData.IsNull()) {
JS::Rooted<JSObject*> buffer(aGlobal.Context(),
aEventInitDict.mInitData.Value().Obj());
e->mInitData = JS::CopyArrayBuffer(aGlobal.Context(), buffer);
const auto& a = aEventInitDict.mInitData.Value();
nsTArray<uint8_t> initData;
CopyArrayBufferViewOrArrayBufferData(a, initData);
e->mInitData = ArrayBuffer::Create(aGlobal.Context(), initData.Length(),
initData.Elements());
if (!e->mInitData) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;

Просмотреть файл

@ -6,7 +6,6 @@
#include "mozilla/dom/MediaKeyMessageEvent.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "js/ArrayBuffer.h"
#include "js/RootingAPI.h"
#include "jsfriendapi.h"
#include "mozilla/dom/Nullable.h"
@ -77,9 +76,10 @@ already_AddRefed<MediaKeyMessageEvent> MediaKeyMessageEvent::Constructor(
RefPtr<MediaKeyMessageEvent> e = new MediaKeyMessageEvent(owner);
bool trusted = e->Init(owner);
e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
JS::Rooted<JSObject*> buffer(aGlobal.Context(),
aEventInitDict.mMessage.Obj());
e->mMessage = JS::CopyArrayBuffer(aGlobal.Context(), buffer);
nsTArray<uint8_t> initData;
CopyArrayBufferViewOrArrayBufferData(aEventInitDict.mMessage, initData);
e->mMessage = ArrayBuffer::Create(aGlobal.Context(), initData.Length(),
initData.Elements());
if (!e->mMessage) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;

Просмотреть файл

@ -35,38 +35,11 @@ extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, uint32_t nbytes);
*
* If and only if an ArrayBuffer is successfully created and returned,
* ownership of |contents| is transferred to the new ArrayBuffer.
*
* Care must be taken that |nbytes| bytes of |content| remain valid for the
* duration of this call. In particular, passing the length/pointer of existing
* typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
* call to this function, it could move those contents to a different location
* and invalidate the provided pointer.
*/
extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(JSContext* cx,
size_t nbytes,
void* contents);
/**
* Create a new ArrayBuffer, whose bytes are set to the values of the bytes in
* the provided ArrayBuffer.
*
* |maybeArrayBuffer| is asserted to be non-null. An error is thrown if
* |maybeArrayBuffer| would fail the |IsArrayBufferObject| test given further
* below or if |maybeArrayBuffer| is detached.
*
* |maybeArrayBuffer| may store its contents in any fashion (i.e. it doesn't
* matter whether |maybeArrayBuffer| was allocated using |JS::NewArrayBuffer|,
* |JS::NewExternalArrayBuffer|, or any other ArrayBuffer-allocating function).
*
* The newly-created ArrayBuffer is effectively creatd as if by
* |JS::NewArrayBufferWithContents| passing in |maybeArrayBuffer|'s internal
* data pointer and length, in a manner safe against |maybeArrayBuffer|'s data
* being moved around by the GC. In particular, the new ArrayBuffer will not
* behave like one created for WASM or asm.js, so it *can* be detached.
*/
extern JS_PUBLIC_API JSObject* CopyArrayBuffer(
JSContext* cx, JS::Handle<JSObject*> maybeArrayBuffer);
using BufferContentsFreeFunc = void (*)(void* contents, void* userData);
/**

Просмотреть файл

@ -18,12 +18,11 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/TaggedAnonymousMemory.h"
#include <algorithm> // std::max, std::min, std::uninitialized_copy_n
#include <algorithm>
#include <string.h>
#ifndef XP_WIN
# include <sys/mman.h>
#endif
#include <tuple> // std::tuple
#ifdef MOZ_VALGRIND
# include <valgrind/memcheck.h>
#endif
@ -412,51 +411,21 @@ bool ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
return true;
}
using ArrayBufferContents = UniquePtr<uint8_t[], JS::FreePolicy>;
static ArrayBufferContents AllocateUninitializedArrayBufferContents(
JSContext* cx, uint32_t nbytes) {
// First attempt a normal allocation.
uint8_t* p =
cx->maybe_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena, nbytes);
if (MOZ_UNLIKELY(!p)) {
// Otherwise attempt a large allocation, calling the
// large-allocation-failure callback if necessary.
p = static_cast<uint8_t*>(cx->runtime()->onOutOfMemoryCanGC(
js::AllocFunction::Malloc, js::ArrayBufferContentsArena, nbytes));
if (!p) {
ReportOutOfMemory(cx);
}
static uint8_t* AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes) {
auto* p =
cx->pod_arena_callocCanGC<uint8_t>(js::ArrayBufferContentsArena, nbytes);
if (!p) {
ReportOutOfMemory(cx);
}
return ArrayBufferContents(p);
return p;
}
static ArrayBufferContents AllocateArrayBufferContents(JSContext* cx,
uint32_t nbytes) {
// First attempt a normal allocation.
uint8_t* p =
cx->maybe_pod_arena_calloc<uint8_t>(js::ArrayBufferContentsArena, nbytes);
if (MOZ_UNLIKELY(!p)) {
// Otherwise attempt a large allocation, calling the
// large-allocation-failure callback if necessary.
p = static_cast<uint8_t*>(cx->runtime()->onOutOfMemoryCanGC(
js::AllocFunction::Calloc, js::ArrayBufferContentsArena, nbytes));
if (!p) {
ReportOutOfMemory(cx);
}
}
return ArrayBufferContents(p);
}
static ArrayBufferContents NewCopiedBufferContents(
JSContext* cx, Handle<ArrayBufferObject*> buffer) {
ArrayBufferContents dataCopy =
AllocateUninitializedArrayBufferContents(cx, buffer->byteLength());
static uint8_t* NewCopiedBufferContents(JSContext* cx,
Handle<ArrayBufferObject*> buffer) {
uint8_t* dataCopy = AllocateArrayBufferContents(cx, buffer->byteLength());
if (dataCopy) {
if (auto count = buffer->byteLength()) {
memcpy(dataCopy.get(), buffer->dataPointer(), count);
memcpy(dataCopy, buffer->dataPointer(), count);
}
}
return dataCopy;
@ -1187,83 +1156,6 @@ ArrayBufferObject* ArrayBufferObject::createForContents(
return buffer;
}
template <ArrayBufferObject::FillContents FillType>
/* static */ std::tuple<ArrayBufferObject*, uint8_t*>
ArrayBufferObject::createBufferAndData(
JSContext* cx, uint32_t nbytes, AutoSetNewObjectMetadata&,
JS::Handle<JSObject*> proto /* = nullptr */) {
MOZ_ASSERT(nbytes <= ArrayBufferObject::MaxBufferByteLength,
"caller must validate the byte count it passes");
// Try fitting the data inline with the object by repurposing fixed-slot
// storage. Add extra fixed slots if necessary to accomplish this, but don't
// exceed the maximum number of fixed slots!
size_t nslots = JSCLASS_RESERVED_SLOTS(&class_);
ArrayBufferContents data;
if (nbytes <= MaxInlineBytes) {
int newSlots = HowMany(nbytes, sizeof(Value));
MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
nslots += newSlots;
} else {
data = (FillType == FillContents::Uninitialized
? AllocateUninitializedArrayBufferContents
: AllocateArrayBufferContents)(cx, nbytes);
if (!data) {
return {nullptr, nullptr};
}
}
MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
gc::AllocKind allocKind = GetArrayBufferGCObjectKind(nslots);
ArrayBufferObject* buffer = NewObjectWithClassProto<ArrayBufferObject>(
cx, nullptr, allocKind, GenericObject);
if (!buffer) {
return {nullptr, nullptr};
}
MOZ_ASSERT(!gc::IsInsideNursery(buffer),
"ArrayBufferObject has a finalizer that must be called to not "
"leak in some cases, so it can't be nursery-allocated");
uint8_t* toFill;
if (data) {
toFill = data.release();
buffer->initialize(nbytes, BufferContents::createMalloced(toFill));
AddCellMemory(buffer, nbytes, MemoryUse::ArrayBufferContents);
} else {
toFill = static_cast<uint8_t*>(buffer->initializeToInlineData(nbytes));
if constexpr (FillType == FillContents::Zero) {
memset(toFill, 0, nbytes);
}
}
return {buffer, toFill};
}
/* static */ ArrayBufferObject* ArrayBufferObject::copy(
JSContext* cx, JS::Handle<ArrayBufferObject*> unwrappedArrayBuffer) {
if (unwrappedArrayBuffer->isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_DETACHED);
return nullptr;
}
uint32_t nbytes = unwrappedArrayBuffer->byteLength();
AutoSetNewObjectMetadata metadata(cx);
auto [buffer, toFill] = createBufferAndData<FillContents::Uninitialized>(
cx, nbytes, metadata, nullptr);
if (!buffer) {
return nullptr;
}
std::uninitialized_copy_n(unwrappedArrayBuffer->dataPointer(), nbytes,
toFill);
return buffer;
}
ArrayBufferObject* ArrayBufferObject::createZeroed(
JSContext* cx, uint32_t nbytes, HandleObject proto /* = nullptr */) {
// 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
@ -1271,9 +1163,50 @@ ArrayBufferObject* ArrayBufferObject::createZeroed(
return nullptr;
}
// Try fitting the data inline with the object by repurposing fixed-slot
// storage. Add extra fixed slots if necessary to accomplish this, but don't
// exceed the maximum number of fixed slots!
size_t nslots = JSCLASS_RESERVED_SLOTS(&class_);
uint8_t* data;
if (nbytes <= MaxInlineBytes) {
int newSlots = HowMany(nbytes, sizeof(Value));
MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
nslots += newSlots;
data = nullptr;
} else {
data = AllocateArrayBufferContents(cx, nbytes);
if (!data) {
return nullptr;
}
}
MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
gc::AllocKind allocKind = GetArrayBufferGCObjectKind(nslots);
AutoSetNewObjectMetadata metadata(cx);
auto [buffer, toFill] =
createBufferAndData<FillContents::Zero>(cx, nbytes, metadata, proto);
Rooted<ArrayBufferObject*> buffer(
cx, NewObjectWithClassProto<ArrayBufferObject>(cx, proto, allocKind,
GenericObject));
if (!buffer) {
if (data) {
js_free(data);
}
return nullptr;
}
MOZ_ASSERT(!gc::IsInsideNursery(buffer),
"ArrayBufferObject has a finalizer that must be called to not "
"leak in some cases, so it can't be nursery-allocated");
if (data) {
buffer->initialize(nbytes, BufferContents::createMalloced(data));
AddCellMemory(buffer, nbytes, MemoryUse::ArrayBufferContents);
} else {
void* inlineData = buffer->initializeToInlineData(nbytes);
memset(inlineData, 0, nbytes);
}
return buffer;
}
@ -1347,7 +1280,7 @@ ArrayBufferObject* ArrayBufferObject::createFromNewRawBuffer(
case MAPPED:
case EXTERNAL: {
// We can't use these data types directly. Make a copy to return.
ArrayBufferContents copiedData = NewCopiedBufferContents(cx, buffer);
uint8_t* copiedData = NewCopiedBufferContents(cx, buffer);
if (!copiedData) {
return nullptr;
}
@ -1355,7 +1288,7 @@ ArrayBufferObject* ArrayBufferObject::createFromNewRawBuffer(
// Detach |buffer|. This immediately releases the currently owned
// contents, freeing or unmapping data in the MAPPED and EXTERNAL cases.
ArrayBufferObject::detach(cx, buffer);
return copiedData.release();
return copiedData;
}
case WASM:
@ -1385,13 +1318,13 @@ ArrayBufferObject::extractStructuredCloneContents(
case INLINE_DATA:
case NO_DATA:
case USER_OWNED: {
ArrayBufferContents copiedData = NewCopiedBufferContents(cx, buffer);
uint8_t* copiedData = NewCopiedBufferContents(cx, buffer);
if (!copiedData) {
return BufferContents::createFailed();
}
ArrayBufferObject::detach(cx, buffer);
return BufferContents::createMalloced(copiedData.release());
return BufferContents::createMalloced(copiedData);
}
case MALLOCED:
@ -1733,39 +1666,6 @@ JS_PUBLIC_API JSObject* JS::NewArrayBufferWithContents(JSContext* cx,
return ArrayBufferObject::createForContents(cx, nbytes, contents);
}
static ArrayBufferObject* UnwrapArrayBuffer(
JSContext* cx, JS::Handle<JSObject*> maybeArrayBuffer) {
JSObject* obj = CheckedUnwrapStatic(maybeArrayBuffer);
if (!obj) {
ReportAccessDenied(cx);
return nullptr;
}
if (!obj->is<ArrayBufferObject>()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_BAD_ARGS);
return nullptr;
}
return &obj->as<ArrayBufferObject>();
}
JS_PUBLIC_API JSObject* JS::CopyArrayBuffer(JSContext* cx,
Handle<JSObject*> arrayBuffer) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
MOZ_ASSERT(arrayBuffer != nullptr);
Rooted<ArrayBufferObject*> unwrappedSource(
cx, UnwrapArrayBuffer(cx, arrayBuffer));
if (!unwrappedSource) {
return nullptr;
}
return ArrayBufferObject::copy(cx, unwrappedSource);
}
JS_PUBLIC_API JSObject* JS::NewExternalArrayBuffer(
JSContext* cx, size_t nbytes, void* data,
JS::BufferContentsFreeFunc freeFunc, void* freeUserData) {

Просмотреть файл

@ -9,8 +9,6 @@
#include "mozilla/Maybe.h"
#include <tuple> // std::tuple
#include "builtin/TypedObjectConstants.h"
#include "gc/Memory.h"
#include "gc/ZoneAllocator.h"
@ -234,13 +232,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
"self-hosted code with burned-in constants must use the "
"correct DETACHED bit value");
enum class FillContents { Zero, Uninitialized };
template <FillContents FillType>
static std::tuple<ArrayBufferObject*, uint8_t*> createBufferAndData(
JSContext* cx, uint32_t nbytes, AutoSetNewObjectMetadata&,
JS::Handle<JSObject*> proto = nullptr);
public:
class BufferContents {
uint8_t* data_;
@ -328,9 +319,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
static ArrayBufferObject* createForContents(JSContext* cx, uint32_t nbytes,
BufferContents contents);
static ArrayBufferObject* copy(
JSContext* cx, JS::Handle<ArrayBufferObject*> unwrappedArrayBuffer);
static ArrayBufferObject* createZeroed(JSContext* cx, uint32_t nbytes,
HandleObject proto = nullptr);

Просмотреть файл

@ -251,6 +251,29 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
/* Clear the pending exception (if any) due to OOM. */
void recoverFromOutOfMemory();
/*
* This variation of calloc will call the large-allocation-failure callback
* on OOM and retry the allocation.
*/
template <typename T>
T* pod_arena_callocCanGC(arena_id_t arena, size_t numElems) {
T* p = maybe_pod_arena_calloc<T>(arena, numElems);
if (MOZ_LIKELY(!!p)) {
return p;
}
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
reportAllocationOverflow();
return nullptr;
}
p = static_cast<T*>(
runtime()->onOutOfMemoryCanGC(js::AllocFunction::Calloc, arena, bytes));
if (!p) {
return nullptr;
}
return p;
}
void reportAllocationOverflow() { js::ReportAllocationOverflow(this); }
void noteTenuredAlloc() { allocsThisZoneSinceMinorGC_++; }