mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 01:35:35 +00:00
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:
parent
b632b808c3
commit
b8809d1e54
@ -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));
|
||||
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 p;
|
||||
}
|
||||
|
||||
return ArrayBufferContents(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_++; }
|
||||
|
Loading…
Reference in New Issue
Block a user