Bug 1069680 - Restore array buffer view trace hook, clean up use of typed array layout constants, r=sfink.

This commit is contained in:
Brian Hackett 2014-09-23 15:45:24 -07:00
Родитель a495f0231b
Коммит 0eb54db50c
6 изменённых файлов: 68 добавлений и 52 удалений

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

@ -1653,11 +1653,11 @@ ReportTypedObjTypeError(JSContext *cx,
/*static*/ void /*static*/ void
TypedObject::obj_trace(JSTracer *trace, JSObject *object) TypedObject::obj_trace(JSTracer *trace, JSObject *object)
{ {
ArrayBufferViewObject::trace(trace, object);
JS_ASSERT(object->is<TypedObject>()); JS_ASSERT(object->is<TypedObject>());
TypedObject &typedObj = object->as<TypedObject>(); TypedObject &typedObj = object->as<TypedObject>();
gc::MarkSlot(trace, &typedObj.getFixedSlotRef(JS_BUFVIEW_SLOT_OWNER), "typed object owner");
// When this is called for compacting GC, the related objects we touch here // When this is called for compacting GC, the related objects we touch here
// may not have had their slots updated yet. Note that this does not apply // may not have had their slots updated yet. Note that this does not apply
// to generational GC because these objects (type descriptors and // to generational GC because these objects (type descriptors and

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

@ -1744,7 +1744,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
const Class *clasp = type->clasp(); const Class *clasp = type->clasp();
if (clasp->trace) { if (clasp->trace) {
// Global objects all have the same trace hook. That hook is safe without barriers // Global objects all have the same trace hook. That hook is safe without barriers
// if the gloal has no custom trace hook of it's own, or has been moved to a different // if the global has no custom trace hook of its own, or has been moved to a different
// compartment, and so can't have one. // compartment, and so can't have one.
JS_ASSERT_IF(runtime()->gc.isIncrementalGCEnabled() && JS_ASSERT_IF(runtime()->gc.isIncrementalGCEnabled() &&
!(clasp->trace == JS_GlobalObjectTraceHook && !(clasp->trace == JS_GlobalObjectTraceHook &&

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

@ -519,6 +519,12 @@ ArrayBufferObject::releaseMappedArray()
DeallocateMappedContent(dataPointer(), byteLength()); DeallocateMappedContent(dataPointer(), byteLength());
} }
uint8_t *
ArrayBufferObject::inlineDataPointer() const
{
return static_cast<uint8_t *>(fixedData(JSCLASS_RESERVED_SLOTS(&class_)));
}
uint8_t * uint8_t *
ArrayBufferObject::dataPointer() const ArrayBufferObject::dataPointer() const
{ {
@ -620,7 +626,7 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, BufferContents content
JS_ASSERT(!gc::IsInsideNursery(obj)); JS_ASSERT(!gc::IsInsideNursery(obj));
if (!contents) { if (!contents) {
void *data = obj->fixedData(reservedSlots); void *data = obj->inlineDataPointer();
memset(data, 0, nbytes); memset(data, 0, nbytes);
obj->initialize(nbytes, BufferContents::createUnowned(data), DoesntOwnData); obj->initialize(nbytes, BufferContents::createUnowned(data), DoesntOwnData);
} else { } else {
@ -772,9 +778,8 @@ ArrayBufferObject::objectMoved(JSObject *obj, const JSObject *old)
const ArrayBufferObject &src = old->as<ArrayBufferObject>(); const ArrayBufferObject &src = old->as<ArrayBufferObject>();
// Fix up possible inline data pointer. // Fix up possible inline data pointer.
const size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&ArrayBufferObject::class_); if (src.hasInlineData())
if (src.dataPointer() == src.fixedData(reservedSlots)) dst.setSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
dst.setSlot(DATA_SLOT, PrivateValue(dst.fixedData(reservedSlots)));
} }
ArrayBufferViewObject * ArrayBufferViewObject *
@ -954,6 +959,27 @@ InnerViewTable::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
* ArrayBufferViewObject * ArrayBufferViewObject
*/ */
/*
* This method is used to trace TypedArrayObjects and DataViewObjects. We need
* a custom tracer to move the object's data pointer if its owner was moved and
* stores its data inline.
*/
/* static */ void
ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
{
HeapSlot &bufSlot = obj->getReservedSlotRef(TypedArrayLayout::BUFFER_SLOT);
MarkSlot(trc, &bufSlot, "typedarray.buffer");
// Update obj's data pointer if the array buffer moved. Note that during
// initialization, bufSlot may still contain |undefined|.
if (bufSlot.isObject()) {
ArrayBufferObject &buf = AsArrayBuffer(MaybeForwarded(&bufSlot.toObject()));
int32_t offset = obj->getReservedSlot(TypedArrayLayout::BYTEOFFSET_SLOT).toInt32();
MOZ_ASSERT(buf.dataPointer() != nullptr);
obj->initPrivate(buf.dataPointer() + offset);
}
}
template <> template <>
bool bool
JSObject::is<js::ArrayBufferViewObject>() const JSObject::is<js::ArrayBufferViewObject>() const

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

@ -247,12 +247,17 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
uint8_t *oldDataPointer, BufferContents newContents); uint8_t *oldDataPointer, BufferContents newContents);
void setFirstView(ArrayBufferViewObject *view); void setFirstView(ArrayBufferViewObject *view);
uint8_t *inlineDataPointer() const;
public: public:
uint8_t *dataPointer() const; uint8_t *dataPointer() const;
size_t byteLength() const; size_t byteLength() const;
BufferContents contents() const { BufferContents contents() const {
return BufferContents(dataPointer(), bufferKind()); return BufferContents(dataPointer(), bufferKind());
} }
bool hasInlineData() const {
return dataPointer() == inlineDataPointer();
}
void releaseData(FreeOp *fop); void releaseData(FreeOp *fop);
@ -325,16 +330,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
class ArrayBufferViewObject : public JSObject class ArrayBufferViewObject : public JSObject
{ {
protected:
/* Offset of view in underlying ArrayBufferObject */
static const size_t BYTEOFFSET_SLOT = JS_BUFVIEW_SLOT_BYTEOFFSET;
/* Byte length of view */
static const size_t LENGTH_SLOT = JS_BUFVIEW_SLOT_LENGTH;
/* Underlying ArrayBufferObject */
static const size_t BUFFER_SLOT = JS_BUFVIEW_SLOT_OWNER;
public: public:
static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj); static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj);
@ -343,6 +338,7 @@ class ArrayBufferViewObject : public JSObject
uint8_t *dataPointer() { uint8_t *dataPointer() {
return static_cast<uint8_t *>(getPrivate()); return static_cast<uint8_t *>(getPrivate());
} }
static void trace(JSTracer *trc, JSObject *obj);
}; };
bool bool

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

@ -92,8 +92,8 @@ TypedArrayLayout::dataOffset()
void void
TypedArrayObject::neuter(void *newData) TypedArrayObject::neuter(void *newData)
{ {
setSlot(LENGTH_SLOT, Int32Value(0)); setSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(0));
setSlot(BYTEOFFSET_SLOT, Int32Value(0)); setSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(0));
setPrivate(newData); setPrivate(newData);
} }
@ -119,7 +119,7 @@ TypedArrayObject::ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarr
memcpy(buffer->dataPointer(), tarray->viewData(), tarray->byteLength()); memcpy(buffer->dataPointer(), tarray->viewData(), tarray->byteLength());
InitArrayBufferViewDataPointer(tarray, buffer, 0); InitArrayBufferViewDataPointer(tarray, buffer, 0);
tarray->setSlot(BUFFER_SLOT, ObjectValue(*buffer)); tarray->setSlot(TypedArrayLayout::BUFFER_SLOT, ObjectValue(*buffer));
return true; return true;
} }
@ -348,7 +348,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
if (!obj) if (!obj)
return nullptr; return nullptr;
obj->setSlot(BUFFER_SLOT, ObjectOrNullValue(buffer)); obj->setSlot(TypedArrayLayout::BUFFER_SLOT, ObjectOrNullValue(buffer));
if (buffer) { if (buffer) {
InitArrayBufferViewDataPointer(obj, buffer, byteOffset); InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
@ -358,8 +358,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject
memset(data, 0, len * sizeof(NativeType)); memset(data, 0, len * sizeof(NativeType));
} }
obj->setSlot(LENGTH_SLOT, Int32Value(len)); obj->setSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(len));
obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset)); obj->setSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(byteOffset));
#ifdef DEBUG #ifdef DEBUG
if (buffer) { if (buffer) {
@ -372,7 +372,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
} }
// Verify that the private slot is at the expected place // Verify that the private slot is at the expected place
JS_ASSERT(obj->numFixedSlots() == DATA_SLOT); JS_ASSERT(obj->numFixedSlots() == TypedArrayLayout::DATA_SLOT);
#endif #endif
if (buffer) { if (buffer) {
@ -950,14 +950,14 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
} }
DataViewObject &dvobj = obj->as<DataViewObject>(); DataViewObject &dvobj = obj->as<DataViewObject>();
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset)); dvobj.setFixedSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(byteOffset));
dvobj.setFixedSlot(LENGTH_SLOT, Int32Value(byteLength)); dvobj.setFixedSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(byteLength));
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer)); dvobj.setFixedSlot(TypedArrayLayout::BUFFER_SLOT, ObjectValue(*arrayBuffer));
InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset); InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
// Verify that the private slot is at the expected place // Verify that the private slot is at the expected place
JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT); JS_ASSERT(dvobj.numFixedSlots() == TypedArrayLayout::DATA_SLOT);
if (!arrayBuffer->addView(cx, &dvobj)) if (!arrayBuffer->addView(cx, &dvobj))
return nullptr; return nullptr;
@ -1722,7 +1722,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
#define IMPL_TYPED_ARRAY_CLASS(_typedArray) \ #define IMPL_TYPED_ARRAY_CLASS(_typedArray) \
{ \ { \
#_typedArray, \ #_typedArray, \
JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | \ JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) | \
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \ JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \
JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \
JS_PropertyStub, /* addProperty */ \ JS_PropertyStub, /* addProperty */ \
@ -1736,7 +1736,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
nullptr, /* call */ \ nullptr, /* call */ \
nullptr, /* hasInstance */ \ nullptr, /* hasInstance */ \
nullptr, /* construct */ \ nullptr, /* construct */ \
nullptr, /* trace */ \ ArrayBufferViewObject::trace, /* trace */ \
TYPED_ARRAY_CLASS_SPEC(_typedArray), \ TYPED_ARRAY_CLASS_SPEC(_typedArray), \
{ \ { \
nullptr, /* outerObject */ \ nullptr, /* outerObject */ \
@ -1895,7 +1895,7 @@ const Class DataViewObject::class_ = {
nullptr, /* call */ nullptr, /* call */
nullptr, /* hasInstance */ nullptr, /* hasInstance */
nullptr, /* construct */ nullptr, /* construct */
nullptr, /* trace */ ArrayBufferViewObject::trace, /* trace */
}; };
const JSFunctionSpec DataViewObject::jsfuncs[] = { const JSFunctionSpec DataViewObject::jsfuncs[] = {
@ -2003,8 +2003,8 @@ DataViewObject::initClass(JSContext *cx)
void void
DataViewObject::neuter(void *newData) DataViewObject::neuter(void *newData)
{ {
setSlot(LENGTH_SLOT, Int32Value(0)); setSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(0));
setSlot(BYTEOFFSET_SLOT, Int32Value(0)); setSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(0));
setPrivate(newData); setPrivate(newData);
} }

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

@ -69,20 +69,14 @@ class TypedArrayLayout
bool isNeuterable() const { return isNeuterable_; } bool isNeuterable() const { return isNeuterable_; }
const Class *addressOfFirstClass() const { return firstClass_; } const Class *addressOfFirstClass() const { return firstClass_; }
const Class *addressOfMaxClass() const { return maxClass_; } const Class *addressOfMaxClass() const { return maxClass_; }
protected:
static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
"bad inlined constant in jsfriendapi.h");
}; };
class TypedArrayObject : public ArrayBufferViewObject class TypedArrayObject : public ArrayBufferViewObject
{ {
protected:
// Typed array properties stored in slots, beyond those shared by all
// ArrayBufferViews.
static const size_t DATA_SLOT = TypedArrayLayout::DATA_SLOT;
static const size_t RESERVED_SLOTS = TypedArrayLayout::RESERVED_SLOTS;
static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
"bad inlined constant in jsfriendapi.h");
public: public:
typedef TypedArrayObject AnyTypedArray; typedef TypedArrayObject AnyTypedArray;
typedef ArrayBufferObject BufferType; typedef ArrayBufferObject BufferType;
@ -107,7 +101,7 @@ class TypedArrayObject : public ArrayBufferViewObject
return &protoClasses[type]; return &protoClasses[type];
} }
static const size_t FIXED_DATA_START = DATA_SLOT + 1; static const size_t FIXED_DATA_START = TypedArrayLayout::DATA_SLOT + 1;
// For typed arrays which can store their data inline, the array buffer // For typed arrays which can store their data inline, the array buffer
// object is created lazily. // object is created lazily.
@ -128,16 +122,16 @@ class TypedArrayObject : public ArrayBufferViewObject
inline size_t bytesPerElement() const; inline size_t bytesPerElement() const;
static Value bufferValue(TypedArrayObject *tarr) { static Value bufferValue(TypedArrayObject *tarr) {
return tarr->getFixedSlot(BUFFER_SLOT); return tarr->getFixedSlot(TypedArrayLayout::BUFFER_SLOT);
} }
static Value byteOffsetValue(TypedArrayObject *tarr) { static Value byteOffsetValue(TypedArrayObject *tarr) {
return tarr->getFixedSlot(BYTEOFFSET_SLOT); return tarr->getFixedSlot(TypedArrayLayout::BYTEOFFSET_SLOT);
} }
static Value byteLengthValue(TypedArrayObject *tarr) { static Value byteLengthValue(TypedArrayObject *tarr) {
return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement()); return Int32Value(tarr->getFixedSlot(TypedArrayLayout::LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
} }
static Value lengthValue(TypedArrayObject *tarr) { static Value lengthValue(TypedArrayObject *tarr) {
return tarr->getFixedSlot(LENGTH_SLOT); return tarr->getFixedSlot(TypedArrayLayout::LENGTH_SLOT);
} }
static bool static bool
@ -164,7 +158,7 @@ class TypedArrayObject : public ArrayBufferViewObject
void *viewData() const { void *viewData() const {
// Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h! // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
return static_cast<void*>(getPrivate(DATA_SLOT)); return static_cast<void*>(getPrivate(TypedArrayLayout::DATA_SLOT));
} }
Value getElement(uint32_t index); Value getElement(uint32_t index);
@ -339,19 +333,19 @@ class DataViewObject : public ArrayBufferViewObject
static const Class class_; static const Class class_;
static Value byteOffsetValue(DataViewObject *view) { static Value byteOffsetValue(DataViewObject *view) {
Value v = view->getReservedSlot(BYTEOFFSET_SLOT); Value v = view->getReservedSlot(TypedArrayLayout::BYTEOFFSET_SLOT);
JS_ASSERT(v.toInt32() >= 0); JS_ASSERT(v.toInt32() >= 0);
return v; return v;
} }
static Value byteLengthValue(DataViewObject *view) { static Value byteLengthValue(DataViewObject *view) {
Value v = view->getReservedSlot(LENGTH_SLOT); Value v = view->getReservedSlot(TypedArrayLayout::LENGTH_SLOT);
JS_ASSERT(v.toInt32() >= 0); JS_ASSERT(v.toInt32() >= 0);
return v; return v;
} }
static Value bufferValue(DataViewObject *view) { static Value bufferValue(DataViewObject *view) {
return view->getReservedSlot(BUFFER_SLOT); return view->getReservedSlot(TypedArrayLayout::BUFFER_SLOT);
} }
uint32_t byteOffset() const { uint32_t byteOffset() const {