Bug 979480 - Don't store array buffer contents in elements, r=sfink.

This commit is contained in:
Brian Hackett 2014-03-17 11:46:04 -06:00
Родитель 1e250fb46a
Коммит c39fd409c3
25 изменённых файлов: 500 добавлений и 1058 удалений

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

@ -3817,8 +3817,7 @@ nsXMLHttpRequestXPCOMifier::GetInterface(const nsIID & aIID, void **aResult)
namespace mozilla { namespace mozilla {
ArrayBufferBuilder::ArrayBufferBuilder() ArrayBufferBuilder::ArrayBufferBuilder()
: mRawContents(nullptr), : mDataPtr(nullptr),
mDataPtr(nullptr),
mCapacity(0), mCapacity(0),
mLength(0) mLength(0)
{ {
@ -3832,20 +3831,22 @@ ArrayBufferBuilder::~ArrayBufferBuilder()
void void
ArrayBufferBuilder::reset() ArrayBufferBuilder::reset()
{ {
if (mRawContents) { if (mDataPtr) {
JS_free(nullptr, mRawContents); JS_free(nullptr, mDataPtr);
} }
mRawContents = mDataPtr = nullptr; mDataPtr = nullptr;
mCapacity = mLength = 0; mCapacity = mLength = 0;
} }
bool bool
ArrayBufferBuilder::setCapacity(uint32_t aNewCap) ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
{ {
if (!JS_ReallocateArrayBufferContents(nullptr, aNewCap, &mRawContents, &mDataPtr)) { uint8_t *newdata = (uint8_t *) JS_ReallocateArrayBufferContents(nullptr, aNewCap, mDataPtr, mCapacity);
if (!newdata) {
return false; return false;
} }
mDataPtr = newdata;
mCapacity = aNewCap; mCapacity = aNewCap;
if (mLength > aNewCap) { if (mLength > aNewCap) {
mLength = aNewCap; mLength = aNewCap;
@ -3903,12 +3904,12 @@ ArrayBufferBuilder::getArrayBuffer(JSContext* aCx)
} }
} }
JSObject* obj = JS_NewArrayBufferWithContents(aCx, mRawContents); JSObject* obj = JS_NewArrayBufferWithContents(aCx, mLength, mDataPtr);
if (!obj) { if (!obj) {
return nullptr; return nullptr;
} }
mRawContents = mDataPtr = nullptr; mDataPtr = nullptr;
mLength = mCapacity = 0; mLength = mCapacity = 0;
return obj; return obj;

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

@ -62,7 +62,6 @@ namespace mozilla {
// or it can be reset explicitly at any point by calling reset(). // or it can be reset explicitly at any point by calling reset().
class ArrayBufferBuilder class ArrayBufferBuilder
{ {
void* mRawContents;
uint8_t* mDataPtr; uint8_t* mDataPtr;
uint32_t mCapacity; uint32_t mCapacity;
uint32_t mLength; uint32_t mLength;

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

@ -198,12 +198,11 @@ StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
for (uint32_t i = 0; i < aJSArrays.Length(); ++i) { for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
JS::Rooted<JSObject*> arrayBuffer(aJSContext, JS::Rooted<JSObject*> arrayBuffer(aJSContext,
JS_GetArrayBufferViewBuffer(aJSArrays[i])); JS_GetArrayBufferViewBuffer(aJSArrays[i]));
void* dataToFree = nullptr; uint8_t* stolenData = arrayBuffer
uint8_t* stolenData = nullptr; ? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
if (arrayBuffer && : nullptr;
JS_StealArrayBufferContents(aJSContext, arrayBuffer, &dataToFree, if (stolenData) {
&stolenData)) { result->SetData(i, stolenData, reinterpret_cast<float*>(stolenData));
result->SetData(i, dataToFree, reinterpret_cast<float*>(stolenData));
} else { } else {
return nullptr; return nullptr;
} }

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

@ -1406,7 +1406,6 @@ TypedObject::createUnattachedWithClass(JSContext *cx,
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0)); obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, NullValue()); obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, NullValue());
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_VIEW, PrivateValue(nullptr)); obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_VIEW, PrivateValue(nullptr));
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_BUFFER, PrivateValue(UNSET_BUFFER_LINK));
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(length)); obj->initReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(length));
obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type)); obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type));
@ -1508,7 +1507,7 @@ TypedObject::createZeroed(JSContext *cx,
{ {
size_t totalSize = descr->as<SizedTypeDescr>().size(); size_t totalSize = descr->as<SizedTypeDescr>().size();
Rooted<ArrayBufferObject*> buffer(cx); Rooted<ArrayBufferObject*> buffer(cx);
buffer = ArrayBufferObject::create(cx, totalSize, false); buffer = ArrayBufferObject::create(cx, totalSize);
if (!buffer) if (!buffer)
return nullptr; return nullptr;
typeRepr->asSized()->initInstance(cx->runtime(), buffer->dataPointer(), 1); typeRepr->asSized()->initInstance(cx->runtime(), buffer->dataPointer(), 1);
@ -1529,7 +1528,7 @@ TypedObject::createZeroed(JSContext *cx,
} }
Rooted<ArrayBufferObject*> buffer(cx); Rooted<ArrayBufferObject*> buffer(cx);
buffer = ArrayBufferObject::create(cx, totalSize, false); buffer = ArrayBufferObject::create(cx, totalSize);
if (!buffer) if (!buffer)
return nullptr; return nullptr;
@ -1723,11 +1722,10 @@ TypedObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs) PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{ {
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
Rooted<jsid> id(cx);
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj)); if (!IndexToId(cx, index, &id))
if (!delegate)
return false; return false;
return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs); return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
} }
bool bool

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

@ -109,15 +109,14 @@
#define JS_TYPEDOBJ_SLOT_BYTELENGTH 1 #define JS_TYPEDOBJ_SLOT_BYTELENGTH 1
#define JS_TYPEDOBJ_SLOT_OWNER 2 #define JS_TYPEDOBJ_SLOT_OWNER 2
#define JS_TYPEDOBJ_SLOT_NEXT_VIEW 3 #define JS_TYPEDOBJ_SLOT_NEXT_VIEW 3
#define JS_TYPEDOBJ_SLOT_NEXT_BUFFER 4
#define JS_DATAVIEW_SLOTS 5 // Number of slots for data views #define JS_DATAVIEW_SLOTS 4 // Number of slots for data views
#define JS_TYPEDOBJ_SLOT_LENGTH 5 // Length of array (see (*) below) #define JS_TYPEDOBJ_SLOT_LENGTH 4 // Length of array (see (*) below)
#define JS_TYPEDOBJ_SLOT_TYPE_DESCR 6 // For typed objects, type descr #define JS_TYPEDOBJ_SLOT_TYPE_DESCR 5 // For typed objects, type descr
#define JS_TYPEDOBJ_SLOT_DATA 7 // private slot, based on alloc kind #define JS_TYPEDOBJ_SLOT_DATA 7 // private slot, based on alloc kind
#define JS_TYPEDOBJ_SLOTS 7 // Number of slots for typed objs #define JS_TYPEDOBJ_SLOTS 6 // Number of slots for typed objs
// (*) The JS_TYPEDOBJ_SLOT_LENGTH slot stores the length for typed objects of // (*) The JS_TYPEDOBJ_SLOT_LENGTH slot stores the length for typed objects of
// sized and unsized array type. The slot contains 0 for non-arrays. // sized and unsized array type. The slot contains 0 for non-arrays.

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

@ -278,24 +278,6 @@ js::Nursery::notifyInitialSlots(Cell *cell, HeapSlot *slots)
} }
} }
void
js::Nursery::notifyNewElements(gc::Cell *cell, ObjectElements *elements)
{
JS_ASSERT(!isInside(elements));
notifyInitialSlots(cell, reinterpret_cast<HeapSlot *>(elements));
}
void
js::Nursery::notifyRemovedElements(gc::Cell *cell, ObjectElements *oldElements)
{
JS_ASSERT(cell);
JS_ASSERT(oldElements);
JS_ASSERT(!isInside(oldElements));
if (isInside(cell))
hugeSlots.remove(reinterpret_cast<HeapSlot *>(oldElements));
}
namespace js { namespace js {
namespace gc { namespace gc {
@ -620,25 +602,6 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi
return 0; return 0;
} }
/* ArrayBuffer stores byte-length, not Value count. */
if (src->is<ArrayBufferObject>()) {
size_t nbytes;
if (src->hasDynamicElements()) {
nbytes = sizeof(ObjectElements) + srcHeader->initializedLength;
dstHeader = static_cast<ObjectElements *>(zone->malloc_(nbytes));
if (!dstHeader)
CrashAtUnhandlableOOM("Failed to allocate array buffer elements while tenuring.");
} else {
dst->setFixedElements();
nbytes = GetGCKindSlots(dst->tenuredGetAllocKind()) * sizeof(HeapSlot);
dstHeader = dst->getElementsHeader();
}
js_memcpy(dstHeader, srcHeader, nbytes);
setElementsForwardingPointer(srcHeader, dstHeader, nbytes / sizeof(HeapSlot));
dst->elements = dstHeader->elements();
return src->hasDynamicElements() ? nbytes : 0;
}
size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity; size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity;
/* Unlike other objects, Arrays can have fixed elements. */ /* Unlike other objects, Arrays can have fixed elements. */
@ -784,7 +747,7 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList
// Update the array buffer object's view lists. // Update the array buffer object's view lists.
TIME_START(sweepArrayBufferViewList); TIME_START(sweepArrayBufferViewList);
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c->gcLiveArrayBuffers) if (!c->gcLiveArrayBuffers.empty())
ArrayBufferObject::sweep(c); ArrayBufferObject::sweep(c);
} }
TIME_END(sweepArrayBufferViewList); TIME_END(sweepArrayBufferViewList);

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

@ -106,12 +106,6 @@ class Nursery
/* Add a slots to our tracking list if it is out-of-line. */ /* Add a slots to our tracking list if it is out-of-line. */
void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots); void notifyInitialSlots(gc::Cell *cell, HeapSlot *slots);
/* Add elements to our tracking list if it is out-of-line. */
void notifyNewElements(gc::Cell *cell, ObjectElements *elements);
/* Remove elements to our tracking list if it is out-of-line. */
void notifyRemovedElements(gc::Cell *cell, ObjectElements *oldElements);
typedef Vector<types::TypeObject *, 0, SystemAllocPolicy> TypeObjectList; typedef Vector<types::TypeObject *, 0, SystemAllocPolicy> TypeObjectList;
/* /*

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

@ -51,8 +51,7 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2)); CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
// Steal the contents // Steal the contents
void *contents; void *contents = JS_StealArrayBufferContents(cx, obj);
CHECK(JS_StealArrayBufferContents(cx, obj, &contents, &data));
CHECK(contents != nullptr); CHECK(contents != nullptr);
CHECK(data != nullptr); CHECK(data != nullptr);
@ -72,7 +71,7 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
CHECK_SAME(v, JSVAL_VOID); CHECK_SAME(v, JSVAL_VOID);
// Transfer to a new ArrayBuffer // Transfer to a new ArrayBuffer
JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, contents)); JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
CHECK(JS_IsArrayBufferObject(dst)); CHECK(JS_IsArrayBufferObject(dst));
data = JS_GetStableArrayBufferData(cx, obj); data = JS_GetStableArrayBufferData(cx, obj);
@ -105,11 +104,8 @@ BEGIN_TEST(testArrayBuffer_bug720949_viewList)
{ {
buffer = JS_NewArrayBuffer(cx, 2000); buffer = JS_NewArrayBuffer(cx, 2000);
JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1)); JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
void *contents; void *contents = JS_StealArrayBufferContents(cx, buffer);
uint8_t *data;
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
CHECK(contents != nullptr); CHECK(contents != nullptr);
CHECK(data != nullptr);
JS_free(nullptr, contents); JS_free(nullptr, contents);
GC(cx); GC(cx);
CHECK(isNeutered(view)); CHECK(isNeutered(view));
@ -133,11 +129,8 @@ BEGIN_TEST(testArrayBuffer_bug720949_viewList)
view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200); view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
// Neuter // Neuter
void *contents; void *contents = JS_StealArrayBufferContents(cx, buffer);
uint8_t *data;
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
CHECK(contents != nullptr); CHECK(contents != nullptr);
CHECK(data != nullptr);
JS_free(nullptr, contents); JS_free(nullptr, contents);
CHECK(isNeutered(view1)); CHECK(isNeutered(view1));

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

@ -3120,47 +3120,38 @@ JS_PUBLIC_API(void)
JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg); JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg);
/* /*
* Create a new array buffer with the given contents, which must have been * Create a new array buffer with the given contents. The new array buffer
* returned by JS_AllocateArrayBufferContents or JS_StealArrayBufferContents. * takes ownership: after calling this function, do not free |contents| or use
* The new array buffer takes ownership. After calling this function, do not * |contents| from another thread.
* free |contents| or use |contents| from another thread.
*/ */
extern JS_PUBLIC_API(JSObject *) extern JS_PUBLIC_API(JSObject *)
JS_NewArrayBufferWithContents(JSContext *cx, void *contents); JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents);
/* /*
* Steal the contents of the given array buffer. The array buffer has its * Steal the contents of the given array buffer. The array buffer has its
* length set to 0 and its contents array cleared. The caller takes ownership * length set to 0 and its contents array cleared. The caller takes ownership
* of |*contents| and must free it or transfer ownership via * of the return value and must free it or transfer ownership via
* JS_NewArrayBufferWithContents when done using it. * JS_NewArrayBufferWithContents when done using it.
* To free |*contents|, call free().
* A pointer to the buffer's data is returned in |*data|. This pointer can
* be used until |*contents| is freed or has its ownership transferred.
*/ */
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(void *)
JS_StealArrayBufferContents(JSContext *cx, JS::HandleObject obj, void **contents, uint8_t **data); JS_StealArrayBufferContents(JSContext *cx, JS::HandleObject obj);
/* /*
* Allocate memory that may be eventually passed to * Allocate memory that may be eventually passed to
* JS_NewArrayBufferWithContents. |maybecx| is optional; if a non-nullptr cx is * JS_NewArrayBufferWithContents. |maybecx| is optional; if a non-nullptr cx is
* given, it will be used for memory accounting and OOM reporting. |nbytes| is * given, it will be used for memory accounting and OOM reporting. |nbytes| is
* the number of payload bytes required. The pointer to pass to * the number of payload bytes required.
* JS_NewArrayBufferWithContents is returned in |contents|. The pointer to the
* |nbytes| of usable memory is returned in |data|. (*|contents| will contain a
* header before |data|.) The only legal operations on *|contents| are to pass
* it to either JS_NewArrayBufferWithContents or
* JS_ReallocateArrayBufferContents, or free it with js_free or JS_free.
*/ */
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(void *)
JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void **contents, uint8_t **data); JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes);
/* /*
* Reallocate memory allocated by JS_AllocateArrayBufferContents, growing or * Reallocate memory allocated by JS_AllocateArrayBufferContents, growing or
* shrinking it as appropriate. The new data pointer will be returned in data. * shrinking it as appropriate. If oldContents is null then this behaves like
* If *contents is nullptr, behaves like JS_AllocateArrayBufferContents. * JS_AllocateArrayBufferContents.
*/ */
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(void *)
JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data); JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void *oldContents, uint32_t oldNbytes);
extern JS_PUBLIC_API(JSIdArray *) extern JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext *cx, JSObject *obj); JS_Enumerate(JSContext *cx, JSObject *obj);

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

@ -58,7 +58,6 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
propertyTree(thisForCtor()), propertyTree(thisForCtor()),
selfHostingScriptSource(nullptr), selfHostingScriptSource(nullptr),
gcIncomingGrayPointers(nullptr), gcIncomingGrayPointers(nullptr),
gcLiveArrayBuffers(nullptr),
gcWeakMapList(nullptr), gcWeakMapList(nullptr),
debugModeBits(runtime_->debugMode ? DebugFromC : 0), debugModeBits(runtime_->debugMode ? DebugFromC : 0),
rngState(0), rngState(0),

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

@ -280,8 +280,8 @@ struct JSCompartment
*/ */
JSObject *gcIncomingGrayPointers; JSObject *gcIncomingGrayPointers;
/* Linked list of live array buffers with >1 view. */ /* During GC, list of live array buffers with >1 view accumulated during tracing. */
js::ArrayBufferObject *gcLiveArrayBuffers; js::ArrayBufferVector gcLiveArrayBuffers;
/* Linked list of live weakmaps in this compartment. */ /* Linked list of live weakmaps in this compartment. */
js::WeakMapBase *gcWeakMapList; js::WeakMapBase *gcWeakMapList;

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

@ -3001,7 +3001,7 @@ BeginMarkPhase(JSRuntime *rt)
} }
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
JS_ASSERT(!c->gcLiveArrayBuffers); JS_ASSERT(c->gcLiveArrayBuffers.empty());
c->marked = false; c->marked = false;
if (ShouldPreserveJITCode(c, currentTime)) if (ShouldPreserveJITCode(c, currentTime))
c->zone()->setPreservingCode(true); c->zone()->setPreservingCode(true);
@ -4253,7 +4253,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
#ifdef DEBUG #ifdef DEBUG
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
JS_ASSERT(!c->gcIncomingGrayPointers); JS_ASSERT(!c->gcIncomingGrayPointers);
JS_ASSERT(!c->gcLiveArrayBuffers); JS_ASSERT(c->gcLiveArrayBuffers.empty());
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
if (e.front().key().kind != CrossCompartmentKey::StringWrapper) if (e.front().key().kind != CrossCompartmentKey::StringWrapper)
@ -4468,7 +4468,7 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
#ifdef DEBUG #ifdef DEBUG
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
JS_ASSERT(!c->gcLiveArrayBuffers); JS_ASSERT(c->gcLiveArrayBuffers.empty());
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
JS_ASSERT(!zone->needsBarrier()); JS_ASSERT(!zone->needsBarrier());

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

@ -5898,17 +5898,7 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Objects
if (hasDynamicElements()) { if (hasDynamicElements()) {
js::ObjectElements *elements = getElementsHeader(); js::ObjectElements *elements = getElementsHeader();
if (MOZ_UNLIKELY(elements->isAsmJSArrayBuffer())) { sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(elements);
#if defined (JS_CPU_X64)
// On x64, ArrayBufferObject::prepareForAsmJS switches the
// ArrayBufferObject to use mmap'd storage.
sizes->nonHeapElementsAsmJS += as<ArrayBufferObject>().byteLength();
#else
sizes->mallocHeapElementsAsmJS += mallocSizeOf(elements);
#endif
} else {
sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(elements);
}
} }
// Other things may be measured in the future if DMD indicates it is worthwhile. // Other things may be measured in the future if DMD indicates it is worthwhile.
@ -5935,6 +5925,8 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Objects
sizes->mallocHeapRegExpStatics += as<RegExpStaticsObject>().sizeOfData(mallocSizeOf); sizes->mallocHeapRegExpStatics += as<RegExpStaticsObject>().sizeOfData(mallocSizeOf);
} else if (is<PropertyIteratorObject>()) { } else if (is<PropertyIteratorObject>()) {
sizes->mallocHeapPropertyIteratorData += as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf); sizes->mallocHeapPropertyIteratorData += as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
} else if (is<ArrayBufferObject>() || is<SharedArrayBufferObject>()) {
ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, sizes);
#ifdef JS_ION #ifdef JS_ION
} else if (is<AsmJSModuleObject>()) { } else if (is<AsmJSModuleObject>()) {
as<AsmJSModuleObject>().addSizeOfMisc(mallocSizeOf, &sizes->nonHeapCodeAsmJS, as<AsmJSModuleObject>().addSizeOfMisc(mallocSizeOf, &sizes->nonHeapCodeAsmJS,

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

@ -527,7 +527,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
obj->privateRef(shape->numFixedSlots()) = nullptr; obj->privateRef(shape->numFixedSlots()) = nullptr;
size_t span = shape->slotSpan(); size_t span = shape->slotSpan();
if (span && clasp != &js::ArrayBufferObject::class_) if (span)
obj->initializeSlotRange(0, span); obj->initializeSlotRange(0, span);
return obj; return obj;
@ -573,12 +573,10 @@ JSObject::finish(js::FreeOp *fop)
{ {
if (hasDynamicSlots()) if (hasDynamicSlots())
fop->free_(slots); fop->free_(slots);
if (hasDynamicElements()) { if (hasDynamicElements()) {
js::ObjectElements *elements = getElementsHeader(); js::ObjectElements *elements = getElementsHeader();
if (MOZ_UNLIKELY(elements->isAsmJSArrayBuffer())) fop->free_(elements);
js::ArrayBufferObject::releaseAsmJSArrayBuffer(fop, this);
else
fop->free_(elements);
} }
} }
@ -941,6 +939,17 @@ NewBuiltinClassInstance(ExclusiveContext *cx, NewObjectKind newKind = GenericObj
return &obj->as<T>(); return &obj->as<T>();
} }
template<typename T>
inline T *
NewBuiltinClassInstance(ExclusiveContext *cx, gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
{
JSObject *obj = NewBuiltinClassInstance(cx, &T::class_, allocKind, newKind);
if (!obj)
return nullptr;
return &obj->as<T>();
}
// Used to optimize calls to (new Object()) // Used to optimize calls to (new Object())
bool bool
NewObjectScriptedCall(JSContext *cx, MutableHandleObject obj); NewObjectScriptedCall(JSContext *cx, MutableHandleObject obj);

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

@ -1025,7 +1025,6 @@ CacheEntry_setBytecode(JSContext *cx, HandleObject cache, uint8_t *buffer, uint3
if (!arrayBuffer || !ArrayBufferObject::ensureNonInline(cx, arrayBuffer)) if (!arrayBuffer || !ArrayBufferObject::ensureNonInline(cx, arrayBuffer))
return false; return false;
memcpy(arrayBuffer->dataPointer(), buffer, length);
SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer)); SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer));
return true; return true;
} }
@ -1284,6 +1283,8 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp)
if (!CacheEntry_setBytecode(cx, cacheEntry, saveBuffer, saveLength)) if (!CacheEntry_setBytecode(cx, cacheEntry, saveBuffer, saveLength))
return false; return false;
saveBuffer.forget();
} }
return JS_WrapValue(cx, args.rval()); return JS_WrapValue(cx, args.rval());
@ -6220,6 +6221,11 @@ main(int argc, char **argv, char **envp)
PR_JoinThread(workerThreads[i]); PR_JoinThread(workerThreads[i]);
#endif #endif
#ifdef JSGC_GENERATIONAL
if (!noggc.empty())
noggc.destroy();
#endif
JS_DestroyRuntime(rt); JS_DestroyRuntime(rt);
JS_ShutDown(); JS_ShutDown();
return result; return result;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -53,6 +53,13 @@ class ArrayBufferObject : public JSObject
static bool fun_slice_impl(JSContext *cx, CallArgs args); static bool fun_slice_impl(JSContext *cx, CallArgs args);
public: public:
static const uint8_t DATA_SLOT = 0;
static const uint8_t BYTE_LENGTH_SLOT = 1;
static const uint8_t VIEW_LIST_SLOT = 2;
static const uint8_t FLAGS_SLOT = 3;
static const uint8_t RESERVED_SLOTS = 4;
static const Class class_; static const Class class_;
static const Class protoClass; static const Class protoClass;
@ -67,7 +74,7 @@ class ArrayBufferObject : public JSObject
static bool class_constructor(JSContext *cx, unsigned argc, Value *vp); static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, bool clear = true, static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, void *contents = nullptr,
NewObjectKind newKind = GenericObject); NewObjectKind newKind = GenericObject);
static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer, static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
@ -84,57 +91,17 @@ class ArrayBufferObject : public JSObject
static void obj_trace(JSTracer *trc, JSObject *obj); static void obj_trace(JSTracer *trc, JSObject *obj);
static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleObject objp, MutableHandleShape propp);
static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleObject objp, MutableHandleShape propp);
static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleObject objp, MutableHandleShape propp);
static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
static bool obj_defineProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp);
static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandlePropertyName name, MutableHandleValue vp);
static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp);
static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, bool strict);
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleValue vp, bool strict);
static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue vp, bool strict);
static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
HandleId id, unsigned *attrsp);
static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
HandleId id, unsigned *attrsp);
static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
bool *succeeded);
static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
bool *succeeded);
static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
MutableHandleValue statep, MutableHandleId idp);
static void sweep(JSCompartment *rt); static void sweep(JSCompartment *rt);
static void resetArrayBufferList(JSCompartment *rt); static void resetArrayBufferList(JSCompartment *rt);
static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector); static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
static void restoreArrayBufferLists(ArrayBufferVector &vector); static void restoreArrayBufferLists(ArrayBufferVector &vector);
static void *stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer);
bool hasStealableContents() const { bool hasStealableContents() const {
// Inline elements strictly adhere to the corresponding buffer. // Inline elements strictly adhere to the corresponding buffer.
if (!hasDynamicElements()) if (!ownsData())
return false; return false;
// asm.js buffer contents are transferred by copying, just like inline // asm.js buffer contents are transferred by copying, just like inline
@ -150,31 +117,12 @@ class ArrayBufferObject : public JSObject
return !isNeutered(); return !isNeutered();
} }
static bool stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents, static void addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf,
uint8_t **data); JS::ObjectsExtraSizes *sizes);
static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
header->initializedLength = bytes;
// NB: one or both of these fields is clobbered by GetViewList to store
// the 'views' link. Set them to 0 to effectively initialize 'views'
// to nullptr.
header->length = 0;
header->capacity = 0;
}
static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
header->flags = 0;
updateElementsHeader(header, bytes);
}
static uint32_t headerInitializedLength(const js::ObjectElements *header) {
return header->initializedLength;
}
void addView(ArrayBufferViewObject *view); void addView(ArrayBufferViewObject *view);
void changeContents(JSContext *cx, ObjectElements *newHeader); void changeContents(JSContext *cx, void *newData);
/* /*
* Ensure data is not stored inline in the object. Used when handing back a * Ensure data is not stored inline in the object. Used when handing back a
@ -182,28 +130,15 @@ class ArrayBufferObject : public JSObject
*/ */
static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer); static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
uint32_t byteLength() const { bool canNeuter(JSContext *cx);
return getElementsHeader()->initializedLength;
}
/* /* Neuter this buffer and all its views. */
* Neuter all views of an ArrayBuffer. static void neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer, void *newData);
*/
static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
uint8_t * dataPointer() const; uint8_t *dataPointer() const;
size_t byteLength() const;
/* void releaseData(FreeOp *fop);
* Discard the ArrayBuffer contents, and use |newHeader| for the buffer's
* new contents. (These new contents are zeroed, of identical size in
* memory as the current contents, but appear to be neutered and of zero
* length. This is purely precautionary against stale indexes that were
* in-bounds with respect to the initial length but would not be after
* neutering. This precaution will be removed once we're sure such stale
* indexing no longer happens.) For asm.js buffers, at least, should
* be called after neuterViews().
*/
void neuter(ObjectElements *newHeader, JSContext *cx);
/* /*
* Check if the arrayBuffer contains any data. This will return false for * Check if the arrayBuffer contains any data. This will return false for
@ -213,19 +148,68 @@ class ArrayBufferObject : public JSObject
return getClass() == &class_; return getClass() == &class_;
} }
bool isSharedArrayBuffer() const { bool isAsmJSArrayBuffer() const { return flags() & ASMJS_BUFFER; }
return getElementsHeader()->isSharedArrayBuffer(); bool isSharedArrayBuffer() const { return flags() & SHARED_BUFFER; }
bool isNeutered() const { return flags() & NEUTERED_BUFFER; }
static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
static void finalize(FreeOp *fop, JSObject *obj);
protected:
enum OwnsState {
DoesntOwnData = 0,
OwnsData = 1,
};
void setDataPointer(void *data, OwnsState ownsState);
void setByteLength(size_t length);
ArrayBufferViewObject *viewList() const;
void setViewList(ArrayBufferViewObject *viewsHead);
void setViewListNoBarrier(ArrayBufferViewObject *viewsHead);
enum ArrayBufferFlags {
// In the gcLiveArrayBuffers list.
IN_LIVE_LIST = 0x1,
// The dataPointer() is owned by this buffer and should be released
// when no longer in use. Releasing the pointer may be done by either
// freeing or unmapping it, and how to do this is determined by the
// buffer's other flags.
OWNS_DATA = 0x2,
ASMJS_BUFFER = 0x4,
SHARED_BUFFER = 0x8,
NEUTERED_BUFFER = 0x10
};
uint32_t flags() const;
void setFlags(uint32_t flags);
bool inLiveList() const { return flags() & IN_LIVE_LIST; }
void setInLiveList(bool value) {
setFlags(value ? (flags() | IN_LIVE_LIST) : (flags() & ~IN_LIVE_LIST));
} }
bool isAsmJSArrayBuffer() const { bool ownsData() const { return flags() & OWNS_DATA; }
return getElementsHeader()->isAsmJSArrayBuffer(); void setOwnsData(OwnsState owns) {
setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
} }
bool isNeutered() const {
return getElementsHeader()->isNeuteredBuffer(); void setIsAsmJSArrayBuffer() { setFlags(flags() | ASMJS_BUFFER); }
void setIsSharedArrayBuffer() { setFlags(flags() | SHARED_BUFFER); }
void setIsNeutered() { setFlags(flags() | NEUTERED_BUFFER); }
void initialize(size_t byteLength, void *data, OwnsState ownsState) {
setByteLength(byteLength);
setFlags(0);
setViewListNoBarrier(nullptr);
setDataPointer(data, ownsState);
} }
static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer); void releaseAsmJSArray(FreeOp *fop);
static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
}; };
/* /*
@ -249,35 +233,24 @@ class ArrayBufferViewObject : public JSObject
/* ArrayBufferObjects point to a linked list of views, chained through this slot */ /* ArrayBufferObjects point to a linked list of views, chained through this slot */
static const size_t NEXT_VIEW_SLOT = JS_TYPEDOBJ_SLOT_NEXT_VIEW; static const size_t NEXT_VIEW_SLOT = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
/*
* When ArrayBufferObjects are traced during GC, they construct a linked
* list of ArrayBufferObjects with more than one view, chained through this
* slot of the first view of each ArrayBufferObject.
*/
static const size_t NEXT_BUFFER_SLOT = JS_TYPEDOBJ_SLOT_NEXT_BUFFER;
public: public:
JSObject *bufferObject() const { JSObject *bufferObject() const {
return &getFixedSlot(BUFFER_SLOT).toObject(); return &getFixedSlot(BUFFER_SLOT).toObject();
} }
ArrayBufferObject *bufferLink() {
return static_cast<ArrayBufferObject*>(getFixedSlot(NEXT_BUFFER_SLOT).toPrivate());
}
inline void setBufferLink(ArrayBufferObject *buffer);
ArrayBufferViewObject *nextView() const { ArrayBufferViewObject *nextView() const {
return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate()); return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
} }
inline void setNextView(ArrayBufferViewObject *view); inline void setNextView(ArrayBufferViewObject *view);
void prependToViews(ArrayBufferViewObject *viewsHead);
void neuter(JSContext *cx); void neuter(JSContext *cx);
static void trace(JSTracer *trc, JSObject *obj); static void trace(JSTracer *trc, JSObject *obj);
uint8_t *dataPointer() {
return static_cast<uint8_t *>(getPrivate());
}
}; };
bool bool
@ -323,13 +296,6 @@ bool IsArrayBuffer(JSObject *obj);
ArrayBufferObject &AsArrayBuffer(HandleObject obj); ArrayBufferObject &AsArrayBuffer(HandleObject obj);
ArrayBufferObject &AsArrayBuffer(JSObject *obj); ArrayBufferObject &AsArrayBuffer(JSObject *obj);
inline void
ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
{
setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
PostBarrierTypedArrayObject(this);
}
inline void inline void
ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view) ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view)
{ {

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

@ -383,20 +383,6 @@ js::ObjectImpl::markChildren(JSTracer *trc)
} }
} }
JSObject *
js::ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj)
{
MOZ_ASSERT(obj->hasClass(&ArrayBufferObject::class_) ||
obj->hasClass(&SharedArrayBufferObject::class_));
if (obj->getPrivate())
return static_cast<JSObject *>(obj->getPrivate());
JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_,
obj->getTaggedProto(), nullptr);
obj->setPrivateGCThing(delegate);
return delegate;
}
void void
AutoPropDescRooter::trace(JSTracer *trc) AutoPropDescRooter::trace(JSTracer *trc)
{ {

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

@ -168,23 +168,16 @@ class ObjectElements
public: public:
enum Flags { enum Flags {
CONVERT_DOUBLE_ELEMENTS = 0x1, CONVERT_DOUBLE_ELEMENTS = 0x1,
ASMJS_ARRAY_BUFFER = 0x2,
NEUTERED_BUFFER = 0x4,
SHARED_ARRAY_BUFFER = 0x8,
// Present only if these elements correspond to an array with // Present only if these elements correspond to an array with
// non-writable length; never present for non-arrays. // non-writable length; never present for non-arrays.
NONWRITABLE_ARRAY_LENGTH = 0x10 NONWRITABLE_ARRAY_LENGTH = 0x2
}; };
private: private:
friend class ::JSObject; friend class ::JSObject;
friend class ObjectImpl; friend class ObjectImpl;
friend class ArrayObject; friend class ArrayObject;
friend class ArrayBufferObject;
friend class ArrayBufferViewObject;
friend class SharedArrayBufferObject;
friend class TypedArrayObject;
friend class Nursery; friend class Nursery;
template <ExecutionMode mode> template <ExecutionMode mode>
@ -231,24 +224,6 @@ class ObjectElements
void clearShouldConvertDoubleElements() { void clearShouldConvertDoubleElements() {
flags &= ~CONVERT_DOUBLE_ELEMENTS; flags &= ~CONVERT_DOUBLE_ELEMENTS;
} }
bool isAsmJSArrayBuffer() const {
return flags & ASMJS_ARRAY_BUFFER;
}
void setIsAsmJSArrayBuffer() {
flags |= ASMJS_ARRAY_BUFFER;
}
bool isNeuteredBuffer() const {
return flags & NEUTERED_BUFFER;
}
void setIsNeuteredBuffer() {
flags |= NEUTERED_BUFFER;
}
bool isSharedArrayBuffer() const {
return flags & SHARED_ARRAY_BUFFER;
}
void setIsSharedArrayBuffer() {
flags |= SHARED_ARRAY_BUFFER;
}
bool hasNonwritableArrayLength() const { bool hasNonwritableArrayLength() const {
return flags & NONWRITABLE_ARRAY_LENGTH; return flags & NONWRITABLE_ARRAY_LENGTH;
} }
@ -1039,9 +1014,6 @@ IsObjectValueInCompartment(js::Value v, JSCompartment *comp)
} }
#endif #endif
extern JSObject *
ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj);
} /* namespace js */ } /* namespace js */
#endif /* vm_ObjectImpl_h */ #endif /* vm_ObjectImpl_h */

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

@ -23,8 +23,6 @@ using namespace js;
using mozilla::IsNaN; using mozilla::IsNaN;
using mozilla::PodCopy; using mozilla::PodCopy;
#define SHAREDARRAYBUFFER_RESERVED_SLOTS 15
/* /*
* SharedArrayRawBuffer * SharedArrayRawBuffer
*/ */
@ -179,53 +177,26 @@ SharedArrayBufferObject::New(JSContext *cx, uint32_t length)
return nullptr; return nullptr;
} }
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
if (!obj)
return nullptr;
JS_ASSERT(obj->getClass() == &class_);
Rooted<js::Shape*> empty(cx);
empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
if (!empty)
return nullptr;
obj->setLastPropertyInfallible(empty);
obj->setFixedElements();
obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(), length);
obj->getElementsHeader()->setIsSharedArrayBuffer();
SharedArrayRawBuffer *buffer = SharedArrayRawBuffer::New(length); SharedArrayRawBuffer *buffer = SharedArrayRawBuffer::New(length);
if (!buffer) if (!buffer)
return nullptr; return nullptr;
obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
return obj; return New(cx, buffer);
} }
JSObject * JSObject *
SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer) SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer)
{ {
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_)); Rooted<SharedArrayBufferObject*> obj(cx, NewBuiltinClassInstance<SharedArrayBufferObject>(cx));
if (!obj) if (!obj)
return nullptr; return nullptr;
JS_ASSERT(obj->getClass() == &class_); JS_ASSERT(obj->getClass() == &class_);
Rooted<js::Shape*> empty(cx); obj->initialize(buffer->byteLength(), nullptr, DoesntOwnData);
empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
if (!empty)
return nullptr;
obj->setLastPropertyInfallible(empty);
obj->setFixedElements(); obj->acceptRawBuffer(buffer);
obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(), obj->setIsSharedArrayBuffer();
buffer->byteLength());
obj->getElementsHeader()->setIsSharedArrayBuffer();
obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
return obj; return obj;
} }
@ -283,8 +254,6 @@ SharedArrayBufferObject::Finalize(FreeOp *fop, JSObject *obj)
const Class SharedArrayBufferObject::protoClass = { const Class SharedArrayBufferObject::protoClass = {
"SharedArrayBufferPrototype", "SharedArrayBufferPrototype",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer), JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */ JS_DeletePropertyStub, /* delProperty */
@ -297,10 +266,8 @@ const Class SharedArrayBufferObject::protoClass = {
const Class SharedArrayBufferObject::class_ = { const Class SharedArrayBufferObject::class_ = {
"SharedArrayBuffer", "SharedArrayBuffer",
JSCLASS_HAS_PRIVATE |
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IMPLEMENTS_BARRIERS |
Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer), JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
JS_PropertyStub, /* addProperty */ JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */ JS_DeletePropertyStub, /* delProperty */
@ -315,29 +282,7 @@ const Class SharedArrayBufferObject::class_ = {
nullptr, /* construct */ nullptr, /* construct */
ArrayBufferObject::obj_trace, ArrayBufferObject::obj_trace,
JS_NULL_CLASS_SPEC, JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT, JS_NULL_CLASS_EXT
{
ArrayBufferObject::obj_lookupGeneric,
ArrayBufferObject::obj_lookupProperty,
ArrayBufferObject::obj_lookupElement,
ArrayBufferObject::obj_defineGeneric,
ArrayBufferObject::obj_defineProperty,
ArrayBufferObject::obj_defineElement,
ArrayBufferObject::obj_getGeneric,
ArrayBufferObject::obj_getProperty,
ArrayBufferObject::obj_getElement,
ArrayBufferObject::obj_setGeneric,
ArrayBufferObject::obj_setProperty,
ArrayBufferObject::obj_setElement,
ArrayBufferObject::obj_getGenericAttributes,
ArrayBufferObject::obj_setGenericAttributes,
ArrayBufferObject::obj_deleteProperty,
ArrayBufferObject::obj_deleteElement,
nullptr, nullptr, /* watch/unwatch */
nullptr, /* slice */
ArrayBufferObject::obj_enumerate,
nullptr, /* thisObject */
}
}; };
JSObject * JSObject *

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

@ -74,8 +74,9 @@ class SharedArrayBufferObject : public ArrayBufferObject
static const Class protoClass; static const Class protoClass;
// Slot used for storing a pointer to the SharedArrayRawBuffer. // Slot used for storing a pointer to the SharedArrayRawBuffer.
// First two slots hold the ObjectElements. static const uint8_t RAWBUF_SLOT = ArrayBufferObject::RESERVED_SLOTS;
static const int32_t RAWBUF_SLOT = 2;
static const uint8_t RESERVED_SLOTS = ArrayBufferObject::RESERVED_SLOTS + 1;
static bool class_constructor(JSContext *cx, unsigned argc, Value *vp); static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);

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

@ -977,6 +977,8 @@ JSStructuredCloneWriter::writeTransferMap()
return false; return false;
if (!out.writePtr(nullptr)) // Pointer to ArrayBuffer contents or to SharedArrayRawBuffer. if (!out.writePtr(nullptr)) // Pointer to ArrayBuffer contents or to SharedArrayRawBuffer.
return false; return false;
if (!out.write(0)) // |byteLength| for an ArrayBuffer, 0 for SharedArrayBuffer
return false;
if (!out.write(0)) // |userdata|, intended to be passed to callbacks. if (!out.write(0)) // |userdata|, intended to be passed to callbacks.
return false; return false;
} }
@ -1006,14 +1008,15 @@ JSStructuredCloneWriter::transferOwnership()
MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point)) == SCTAG_TM_UNFILLED); MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point)) == SCTAG_TM_UNFILLED);
if (obj->is<ArrayBufferObject>()) { if (obj->is<ArrayBufferObject>()) {
void *content; size_t nbytes = obj->as<ArrayBufferObject>().byteLength();
uint8_t *data; void *contents = JS_StealArrayBufferContents(context(), obj);
if (!JS_StealArrayBufferContents(context(), obj, &content, &data)) if (!contents)
return false; // Destructor will clean up the already-transferred data return false; // Destructor will clean up the already-transferred data
uint64_t entryTag = PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA); uint64_t entryTag = PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA);
LittleEndian::writeUint64(point++, entryTag); LittleEndian::writeUint64(point++, entryTag);
LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content)); LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(contents));
LittleEndian::writeUint64(point++, nbytes);
LittleEndian::writeUint64(point++, 0); LittleEndian::writeUint64(point++, 0);
} else { } else {
SharedArrayRawBuffer *rawbuf = obj->as<SharedArrayBufferObject>().rawBufferObject(); SharedArrayRawBuffer *rawbuf = obj->as<SharedArrayBufferObject>().rawBufferObject();
@ -1026,6 +1029,7 @@ JSStructuredCloneWriter::transferOwnership()
LittleEndian::writeUint64(point++, entryTag); LittleEndian::writeUint64(point++, entryTag);
LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(rawbuf)); LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(rawbuf));
LittleEndian::writeUint64(point++, 0); LittleEndian::writeUint64(point++, 0);
LittleEndian::writeUint64(point++, 0);
} }
} }
@ -1512,6 +1516,10 @@ JSStructuredCloneReader::readTransferMap()
if (!in.readPtr(&content)) if (!in.readPtr(&content))
return false; return false;
uint64_t nbytes;
if (!in.read(&nbytes))
return false;
uint64_t userdata; uint64_t userdata;
if (!in.read(&userdata)) if (!in.read(&userdata))
return false; return false;
@ -1519,7 +1527,7 @@ JSStructuredCloneReader::readTransferMap()
RootedObject obj(context()); RootedObject obj(context());
if (data == SCTAG_TM_ALLOC_DATA) if (data == SCTAG_TM_ALLOC_DATA)
obj = JS_NewArrayBufferWithContents(context(), content); obj = JS_NewArrayBufferWithContents(context(), nbytes, content);
else if (data == SCTAG_TM_SHARED_BUFFER) else if (data == SCTAG_TM_SHARED_BUFFER)
obj = SharedArrayBufferObject::New(context(), (SharedArrayRawBuffer *)content); obj = SharedArrayBufferObject::New(context(), (SharedArrayRawBuffer *)content);

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

@ -349,7 +349,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset)); obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType))); obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType)));
obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr)); obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
obj->setSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(), js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
obj->getProto(), obj->getParent(), obj->getMetadata(), obj->getProto(), obj->getParent(), obj->getMetadata(),
@ -1344,7 +1343,6 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength)); dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer)); dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr)); dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
dvobj.setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset); InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());

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

@ -337,7 +337,7 @@ ClampIntForUint8Array(int32_t x)
return x; return x;
} }
extern js::ArrayBufferObject * const UNSET_BUFFER_LINK; bool ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d);
} // namespace js } // namespace js

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

@ -64,10 +64,6 @@ namespace {
* and into JavaScript without copy. * and into JavaScript without copy.
*/ */
struct ArrayBufferContents { struct ArrayBufferContents {
/**
* The header of the ArrayBuffer. This is the pointer actually used by JSAPI.
*/
void* header;
/** /**
* The data of the ArrayBuffer. This is the pointer manipulated to * The data of the ArrayBuffer. This is the pointer manipulated to
* read/write the contents of the buffer. * read/write the contents of the buffer.
@ -85,12 +81,11 @@ struct ArrayBufferContents {
struct ScopedArrayBufferContentsTraits { struct ScopedArrayBufferContentsTraits {
typedef ArrayBufferContents type; typedef ArrayBufferContents type;
const static type empty() { const static type empty() {
type result = {0, 0, 0}; type result = {0, 0};
return result; return result;
} }
const static void release(type ptr) { const static void release(type ptr) {
js_free(ptr.header); js_free(ptr.data);
ptr.header = nullptr;
ptr.data = nullptr; ptr.data = nullptr;
ptr.nbytes = 0; ptr.nbytes = 0;
} }
@ -119,10 +114,9 @@ struct ScopedArrayBufferContents: public Scoped<ScopedArrayBufferContentsTraits>
bool Allocate(uint32_t length) { bool Allocate(uint32_t length) {
dispose(); dispose();
ArrayBufferContents& value = rwget(); ArrayBufferContents& value = rwget();
if (JS_AllocateArrayBufferContents(/*no context available*/nullptr, void *ptr = JS_AllocateArrayBufferContents(/*no context available*/nullptr, length);
length, if (ptr) {
&value.header, value.data = (uint8_t *) ptr;
&value.data)) {
value.nbytes = length; value.nbytes = length;
return true; return true;
} }
@ -360,7 +354,7 @@ nsresult
TypedArrayResult::GetCacheableResult(JSContext* cx, JS::MutableHandle<JS::Value> aResult) TypedArrayResult::GetCacheableResult(JSContext* cx, JS::MutableHandle<JS::Value> aResult)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
// We cannot simply construct a typed array using contents.header as // We cannot simply construct a typed array using contents.data as
// this would allow us to have several otherwise unrelated // this would allow us to have several otherwise unrelated
// ArrayBuffers with the same underlying C buffer. As this would be // ArrayBuffers with the same underlying C buffer. As this would be
// very unsafe, we need to cache the result once we have it. // very unsafe, we need to cache the result once we have it.
@ -369,7 +363,7 @@ TypedArrayResult::GetCacheableResult(JSContext* cx, JS::MutableHandle<JS::Value>
MOZ_ASSERT(contents.data); MOZ_ASSERT(contents.data);
JS::Rooted<JSObject*> JS::Rooted<JSObject*>
arrayBuffer(cx, JS_NewArrayBufferWithContents(cx, contents.header)); arrayBuffer(cx, JS_NewArrayBufferWithContents(cx, contents.nbytes, contents.data));
if (!arrayBuffer) { if (!arrayBuffer) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }