Bug 741040 - Make an ArrayBufferObject subclass of JSOBject. r=Waldo

--HG--
extra : rebase_source : 63dd1cc69cfae37203c1f037d5a4b0b5c5651e7b
This commit is contained in:
Steve Fink 2012-03-28 14:43:01 -07:00
parent ebafdfcab0
commit 73e692d5bb
8 changed files with 242 additions and 202 deletions

View File

@ -1782,7 +1782,7 @@ static JSStdName standard_class_atoms[] = {
{js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
#endif
{js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::slowClass},
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
{js_InitWeakMapClass, EAGER_CLASS_ATOM(WeakMap), &js::WeakMapClass},
{js_InitMapClass, EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
{js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_},

View File

@ -461,9 +461,9 @@ JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
bool
JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj)
{
obj = ArrayBuffer::getArrayBuffer(obj);
return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, obj->arrayBufferByteLength()) &&
out.writeBytes(obj->arrayBufferDataOffset(), obj->arrayBufferByteLength());
ArrayBufferObject &buffer = obj->asArrayBuffer();
return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer.byteLength()) &&
out.writeBytes(buffer.dataPointer(), buffer.byteLength());
}
bool
@ -573,7 +573,7 @@ JSStructuredCloneWriter::startWrite(const Value &v)
return startObject(obj);
} else if (obj->isTypedArray()) {
return writeTypedArray(obj);
} else if (obj->isArrayBuffer()) {
} else if (obj->isArrayBuffer() && obj->asArrayBuffer().hasData()) {
return writeArrayBuffer(obj);
} else if (obj->isBoolean()) {
return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->asBoolean().unbox());
@ -778,12 +778,13 @@ JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp
bool
JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
{
JSObject *obj = ArrayBuffer::create(context(), nbytes);
JSObject *obj = ArrayBufferObject::create(context(), nbytes);
if (!obj)
return false;
vp->setObject(*obj);
JS_ASSERT(obj->arrayBufferByteLength() == nbytes);
return in.readArray(obj->arrayBufferDataOffset(), nbytes);
ArrayBufferObject &buffer = obj->asArrayBuffer();
JS_ASSERT(buffer.byteLength() == nbytes);
return in.readArray(buffer.dataPointer(), nbytes);
}
bool

View File

@ -1778,7 +1778,7 @@ TypeSet::getTypedArrayType(JSContext *cx)
if (!proto)
continue;
int objArrayType = proto->getClass() - TypedArray::slowClasses;
int objArrayType = proto->getClass() - TypedArray::protoClasses;
JS_ASSERT(objArrayType >= 0 && objArrayType < TypedArray::TYPE_MAX);
/*

View File

@ -255,6 +255,7 @@ extern Class WithClass;
extern Class XMLFilterClass;
class ArgumentsObject;
class ArrayBufferObject;
class BlockObject;
class BooleanObject;
class ClonedBlockObject;
@ -627,11 +628,6 @@ struct JSObject : public js::ObjectImpl
*/
bool arrayGetOwnDataElement(JSContext *cx, size_t i, js::Value *vp);
public:
bool allocateArrayBufferSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
inline uint32_t arrayBufferByteLength();
inline uint8_t * arrayBufferDataOffset();
public:
/*
* Date-specific getters and setters.
@ -965,6 +961,7 @@ struct JSObject : public js::ObjectImpl
inline bool isCrossCompartmentWrapper() const;
inline js::ArgumentsObject &asArguments();
inline js::ArrayBufferObject &asArrayBuffer();
inline const js::ArgumentsObject &asArguments() const;
inline js::BlockObject &asBlock();
inline js::BooleanObject &asBoolean();

View File

@ -111,7 +111,7 @@ ValueIsLength(JSContext *cx, const Value &v, uint32_t *len)
/*
* Convert |v| to an array index for an array of length |length| per
* the Typed Array Specification section 7.0, |subarray|. If successful,
* the output value is in the range [0, length).
* the output value is in the range [0, length).
*/
static bool
ToClampedIndex(JSContext *cx, const Value &v, int32_t length, int32_t *out)
@ -142,7 +142,7 @@ ToClampedIndex(JSContext *cx, const Value &v, int32_t length, int32_t *out)
* first.
*/
JSObject *
ArrayBuffer::getArrayBuffer(JSObject *obj)
ArrayBufferObject::getArrayBuffer(JSObject *obj)
{
while (obj && !obj->isArrayBuffer())
obj = obj->getProto();
@ -150,19 +150,21 @@ ArrayBuffer::getArrayBuffer(JSObject *obj)
}
JSBool
ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
ArrayBufferObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
JSObject *arrayBuffer = getArrayBuffer(obj);
if (!arrayBuffer) {
JSObject *bufobj = getArrayBuffer(obj);
if (!bufobj) {
vp->setInt32(0);
return true;
}
vp->setInt32(int32_t(arrayBuffer->arrayBufferByteLength()));
ArrayBufferObject &arrayBuffer = bufobj->asArrayBuffer();
vp->setInt32(int32_t(arrayBuffer.byteLength()));
return true;
}
JSBool
ArrayBuffer::fun_slice(JSContext *cx, unsigned argc, Value *vp)
ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@ -171,12 +173,10 @@ ArrayBuffer::fun_slice(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return ok;
JSObject *arrayBuffer = getArrayBuffer(obj);
if (!arrayBuffer)
return true;
ArrayBufferObject &arrayBuffer = obj->asArrayBuffer();
// these are the default values
int32_t length = int32_t(arrayBuffer->arrayBufferByteLength());
int32_t length = int32_t(arrayBuffer.byteLength());
int32_t begin = 0, end = length;
if (args.length() > 0) {
@ -203,13 +203,23 @@ ArrayBuffer::fun_slice(JSContext *cx, unsigned argc, Value *vp)
* new ArrayBuffer(byteLength)
*/
JSBool
ArrayBuffer::class_constructor(JSContext *cx, unsigned argc, Value *vp)
ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
int32_t nbytes = 0;
if (argc > 0 && !ToInt32(cx, vp[2], &nbytes))
return false;
JSObject *bufobj = create(cx, nbytes);
if (nbytes < 0) {
/*
* We're just not going to support arrays that are bigger than what will fit
* as an integer value; if someone actually ever complains (validly), then we
* can fix.
*/
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
JSObject *bufobj = create(cx, uint32_t(nbytes));
if (!bufobj)
return false;
vp->setObject(*bufobj);
@ -217,10 +227,10 @@ ArrayBuffer::class_constructor(JSContext *cx, unsigned argc, Value *vp)
}
bool
JSObject::allocateArrayBufferSlots(JSContext *cx, uint32_t size, uint8_t *contents)
ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents)
{
/*
* ArrayBuffer objects delegate added properties to another JSObject, so
* ArrayBufferObjects delegate added properties to another JSObject, so
* their internal layout can use the object's fixed slots for storage.
* Set up the object to look like an array with an elements header.
*/
@ -270,9 +280,9 @@ DelegateObject(JSContext *cx, JSObject *obj)
}
JSObject *
ArrayBuffer::create(JSContext *cx, int32_t nbytes, uint8_t *contents)
ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents)
{
JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::slowClass);
JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBufferObject::protoClass);
if (!obj)
return NULL;
#ifdef JS_THREADSAFE
@ -281,17 +291,7 @@ ArrayBuffer::create(JSContext *cx, int32_t nbytes, uint8_t *contents)
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT16);
#endif
if (nbytes < 0) {
/*
* We're just not going to support arrays that are bigger than what will fit
* as an integer value; if someone actually ever complains (validly), then we
* can fix.
*/
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
return NULL;
}
JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
JS_ASSERT(obj->getClass() == &ArrayBufferObject::protoClass);
js::Shape *empty = EmptyShape::getInitialShape(cx, &ArrayBufferClass,
obj->getProto(), obj->getParent(),
@ -304,31 +304,29 @@ ArrayBuffer::create(JSContext *cx, int32_t nbytes, uint8_t *contents)
* The first 8 bytes hold the length.
* The rest of it is a flat data store for the array buffer.
*/
if (!obj->allocateArrayBufferSlots(cx, nbytes, contents))
if (!obj->asArrayBuffer().allocateSlots(cx, nbytes, contents))
return NULL;
return obj;
}
JSObject *
ArrayBuffer::createSlice(JSContext *cx, JSObject *arrayBuffer, uint32_t begin, uint32_t end)
ArrayBufferObject::createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
uint32_t begin, uint32_t end)
{
JS_ASSERT(arrayBuffer->isArrayBuffer());
JS_ASSERT(begin <= arrayBuffer->arrayBufferByteLength());
JS_ASSERT(end <= arrayBuffer->arrayBufferByteLength());
JS_ASSERT(begin <= arrayBuffer.byteLength());
JS_ASSERT(end <= arrayBuffer.byteLength());
JS_ASSERT(begin <= end);
uint32_t length = end - begin;
return create(cx, length, arrayBuffer->arrayBufferDataOffset() + begin);
}
if (arrayBuffer.hasData())
return create(cx, length, arrayBuffer.dataPointer() + begin);
ArrayBuffer::~ArrayBuffer()
{
return create(cx, 0);
}
void
ArrayBuffer::obj_trace(JSTracer *trc, JSObject *obj)
ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
{
/*
* If this object changes, it will get marked via the private data barrier,
@ -344,8 +342,8 @@ ArrayBuffer::obj_trace(JSTracer *trc, JSObject *obj)
static JSProperty * const PROPERTY_FOUND = reinterpret_cast<JSProperty *>(1);
JSBool
ArrayBuffer::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp)
ArrayBufferObject::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp)
{
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
*propp = PROPERTY_FOUND;
@ -384,15 +382,15 @@ ArrayBuffer::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
}
JSBool
ArrayBuffer::obj_lookupProperty(JSContext *cx, JSObject *obj, PropertyName *name,
JSObject **objp, JSProperty **propp)
ArrayBufferObject::obj_lookupProperty(JSContext *cx, JSObject *obj, PropertyName *name,
JSObject **objp, JSProperty **propp)
{
return obj_lookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
}
JSBool
ArrayBuffer::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index,
JSObject **objp, JSProperty **propp)
ArrayBufferObject::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index,
JSObject **objp, JSProperty **propp)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -422,15 +420,15 @@ ArrayBuffer::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index,
}
JSBool
ArrayBuffer::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
JSObject **objp, JSProperty **propp)
ArrayBufferObject::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
JSObject **objp, JSProperty **propp)
{
return obj_lookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
}
JSBool
ArrayBuffer::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
ArrayBufferObject::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
return true;
@ -442,15 +440,16 @@ ArrayBuffer::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Valu
}
JSBool
ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
ArrayBufferObject::obj_defineProperty(JSContext *cx, JSObject *obj,
PropertyName *name, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
}
JSBool
ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
ArrayBufferObject::obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -459,18 +458,19 @@ ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, con
}
JSBool
ArrayBuffer::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
ArrayBufferObject::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
}
JSBool
ArrayBuffer::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
ArrayBufferObject::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
{
obj = getArrayBuffer(obj);
JS_ASSERT(obj);
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
vp->setInt32(obj->arrayBufferByteLength());
vp->setInt32(obj->asArrayBuffer().byteLength());
return true;
}
@ -481,12 +481,12 @@ ArrayBuffer::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, js
}
JSBool
ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
Value *vp)
ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj,
JSObject *receiver, PropertyName *name, Value *vp)
{
obj = getArrayBuffer(obj);
if (name == cx->runtime->atomState.byteLengthAtom) {
vp->setInt32(obj->arrayBufferByteLength());
vp->setInt32(obj->asArrayBuffer().byteLength());
return true;
}
@ -497,7 +497,8 @@ ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, P
}
JSBool
ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
ArrayBufferObject::obj_getElement(JSContext *cx, JSObject *obj,
JSObject *receiver, uint32_t index, Value *vp)
{
RootedVarObject delegate(cx, DelegateObject(cx, getArrayBuffer(obj)));
if (!delegate)
@ -506,8 +507,8 @@ ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, ui
}
JSBool
ArrayBuffer::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver,
uint32_t index, Value *vp, bool *present)
ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver,
uint32_t index, Value *vp, bool *present)
{
JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
if (!delegate)
@ -516,13 +517,14 @@ ArrayBuffer::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *rec
}
JSBool
ArrayBuffer::obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
ArrayBufferObject::obj_getSpecial(JSContext *cx, JSObject *obj,
JSObject *receiver, SpecialId sid, Value *vp)
{
return obj_getGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
}
JSBool
ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
ArrayBufferObject::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
{
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
return true;
@ -577,13 +579,15 @@ ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JS
}
JSBool
ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
ArrayBufferObject::obj_setProperty(JSContext *cx, JSObject *obj,
PropertyName *name, Value *vp, JSBool strict)
{
return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
}
JSBool
ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
ArrayBufferObject::obj_setElement(JSContext *cx, JSObject *obj,
uint32_t index, Value *vp, JSBool strict)
{
RootedVarObject delegate(cx, DelegateObject(cx, obj));
if (!delegate)
@ -593,13 +597,15 @@ ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value
}
JSBool
ArrayBuffer::obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
ArrayBufferObject::obj_setSpecial(JSContext *cx, JSObject *obj,
SpecialId sid, Value *vp, JSBool strict)
{
return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
}
JSBool
ArrayBuffer::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, JSObject *obj,
jsid id, unsigned *attrsp)
{
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
*attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
@ -613,13 +619,15 @@ ArrayBuffer::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uns
}
JSBool
ArrayBuffer::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
ArrayBufferObject::obj_getPropertyAttributes(JSContext *cx, JSObject *obj,
PropertyName *name, unsigned *attrsp)
{
return obj_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
}
JSBool
ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
ArrayBufferObject::obj_getElementAttributes(JSContext *cx, JSObject *obj,
uint32_t index, unsigned *attrsp)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -628,13 +636,15 @@ ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32_t ind
}
JSBool
ArrayBuffer::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
ArrayBufferObject::obj_getSpecialAttributes(JSContext *cx, JSObject *obj,
SpecialId sid, unsigned *attrsp)
{
return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
}
JSBool
ArrayBuffer::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, JSObject *obj,
jsid id, unsigned *attrsp)
{
if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@ -649,13 +659,15 @@ ArrayBuffer::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uns
}
JSBool
ArrayBuffer::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
ArrayBufferObject::obj_setPropertyAttributes(JSContext *cx, JSObject *obj,
PropertyName *name, unsigned *attrsp)
{
return obj_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
}
JSBool
ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
ArrayBufferObject::obj_setElementAttributes(JSContext *cx, JSObject *obj,
uint32_t index, unsigned *attrsp)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -664,13 +676,15 @@ ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32_t ind
}
JSBool
ArrayBuffer::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
ArrayBufferObject::obj_setSpecialAttributes(JSContext *cx, JSObject *obj,
SpecialId sid, unsigned *attrsp)
{
return obj_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
}
JSBool
ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
ArrayBufferObject::obj_deleteProperty(JSContext *cx, JSObject *obj,
PropertyName *name, Value *rval, JSBool strict)
{
if (name == cx->runtime->atomState.byteLengthAtom) {
rval->setBoolean(false);
@ -684,7 +698,8 @@ ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name
}
JSBool
ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
ArrayBufferObject::obj_deleteElement(JSContext *cx, JSObject *obj,
uint32_t index, Value *rval, JSBool strict)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -693,7 +708,8 @@ ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Val
}
JSBool
ArrayBuffer::obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
ArrayBufferObject::obj_deleteSpecial(JSContext *cx, JSObject *obj,
SpecialId sid, Value *rval, JSBool strict)
{
JSObject *delegate = DelegateObject(cx, obj);
if (!delegate)
@ -702,15 +718,15 @@ ArrayBuffer::obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Valu
}
JSBool
ArrayBuffer::obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
Value *statep, jsid *idp)
ArrayBufferObject::obj_enumerate(JSContext *cx, JSObject *obj,
JSIterateOp enum_op, Value *statep, jsid *idp)
{
statep->setNull();
return true;
}
JSType
ArrayBuffer::obj_typeOf(JSContext *cx, JSObject *obj)
ArrayBufferObject::obj_typeOf(JSContext *cx, JSObject *obj)
{
return JSTYPE_OBJECT;
}
@ -1019,9 +1035,9 @@ class TypedArrayTemplate
static const size_t BYTES_PER_ELEMENT = sizeof(ThisType);
static inline Class *slowClass()
static inline Class *protoClass()
{
return &TypedArray::slowClasses[ArrayTypeID()];
return &TypedArray::protoClasses[ArrayTypeID()];
}
static inline Class *fastClass()
@ -1367,8 +1383,7 @@ class TypedArrayTemplate
static JSObject *
createTypedArray(JSContext *cx, JSObject *bufobj, uint32_t byteOffset, uint32_t len)
{
JS_ASSERT(bufobj->isArrayBuffer());
JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
JSObject *obj = NewBuiltinClassInstance(cx, protoClass());
if (!obj)
return NULL;
#ifdef JS_THREADSAFE
@ -1381,7 +1396,7 @@ class TypedArrayTemplate
* Specialize the type of the object on the current scripted location,
* and mark the type as definitely a typed array.
*/
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(slowClass());
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(protoClass());
types::TypeObject *type = types::GetTypeCallerInitObject(cx, key);
if (!type)
return NULL;
@ -1390,24 +1405,21 @@ class TypedArrayTemplate
obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
JS_ASSERT(bufobj->isArrayBuffer());
ArrayBufferObject &buffer = bufobj->asArrayBuffer();
/*
* N.B. The base of the array's data is stored in the object's
* private data rather than a slot, to avoid alignment restrictions
* on private Values.
*/
obj->setPrivate(bufobj->arrayBufferDataOffset() + byteOffset);
obj->setPrivate(buffer.dataPointer() + byteOffset);
obj->setSlot(FIELD_LENGTH, Int32Value(len));
obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType)));
DebugOnly<uint32_t> bufferByteLength = bufobj->arrayBufferByteLength();
JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
JS_ASSERT(getBuffer(obj)->arrayBufferDataOffset() <= getDataOffset(obj));
JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
JS_ASSERT(obj->getClass() == slowClass());
JS_ASSERT(obj->getClass() == protoClass());
js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
obj->getProto(), obj->getParent(),
@ -1417,6 +1429,12 @@ class TypedArrayTemplate
return NULL;
obj->setLastPropertyInfallible(empty);
DebugOnly<uint32_t> bufferByteLength = buffer.byteLength();
JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
JS_ASSERT(buffer.dataPointer() <= getDataOffset(obj));
JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
return obj;
@ -1431,7 +1449,7 @@ class TypedArrayTemplate
static JSBool
class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
/* N.B. this is a constructor for slowClass, not fastClass! */
/* N.B. this is a constructor for protoClass, not fastClass! */
JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
if (!obj)
return false;
@ -1620,20 +1638,22 @@ class TypedArrayTemplate
public:
static JSObject *
createTypedArrayWithBuffer(JSContext *cx, JSObject *buffer,
createTypedArrayWithBuffer(JSContext *cx, JSObject *bufobj,
int32_t byteOffsetInt, int32_t lengthInt)
{
uint32_t boffset = (byteOffsetInt == -1) ? 0 : uint32_t(byteOffsetInt);
if (boffset > buffer->arrayBufferByteLength() || boffset % sizeof(NativeType) != 0) {
ArrayBufferObject &buffer = bufobj->asArrayBuffer();
if (boffset > buffer.byteLength() || boffset % sizeof(NativeType) != 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // invalid byteOffset
}
uint32_t len;
if (lengthInt == -1) {
len = (buffer->arrayBufferByteLength() - boffset) / sizeof(NativeType);
if (len * sizeof(NativeType) != buffer->arrayBufferByteLength() - boffset) {
len = (buffer.byteLength() - boffset) / sizeof(NativeType);
if (len * sizeof(NativeType) != buffer.byteLength() - boffset) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // given byte array doesn't map exactly to sizeof(NativeType) * N
}
@ -1648,12 +1668,12 @@ class TypedArrayTemplate
return NULL; // overflow when calculating boffset + len * sizeof(NativeType)
}
if (arrayByteLength + boffset > buffer->arrayBufferByteLength()) {
if (arrayByteLength + boffset > buffer.byteLength()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // boffset + len is too big for the arraybuffer
}
return createTypedArray(cx, buffer, boffset, len);
return createTypedArray(cx, bufobj, boffset, len);
}
static JSObject *
@ -1768,7 +1788,7 @@ class TypedArrayTemplate
static bool
copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj,
JSObject *ar, uint32_t len, uint32_t offset = 0)
JSObject *ar, uint32_t len, uint32_t offset = 0)
{
thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
JS_ASSERT(thisTypedArrayObj);
@ -1971,8 +1991,8 @@ class TypedArrayTemplate
return NULL;
}
int32_t bytelen = size * count;
return ArrayBuffer::create(cx, bytelen);
uint32_t bytelen = size * count;
return ArrayBufferObject::create(cx, bytelen);
}
};
@ -2106,11 +2126,11 @@ TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, ui
***/
/*
* ArrayBuffer (base)
* ArrayBufferObject (base)
*/
Class ArrayBuffer::slowClass = {
"ArrayBuffer",
Class ArrayBufferObject::protoClass = {
"ArrayBufferPrototype",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
@ -2142,53 +2162,53 @@ Class js::ArrayBufferClass = {
NULL, /* call */
NULL, /* construct */
NULL, /* hasInstance */
ArrayBuffer::obj_trace,
ArrayBufferObject::obj_trace,
JS_NULL_CLASS_EXT,
{
ArrayBuffer::obj_lookupGeneric,
ArrayBuffer::obj_lookupProperty,
ArrayBuffer::obj_lookupElement,
ArrayBuffer::obj_lookupSpecial,
ArrayBuffer::obj_defineGeneric,
ArrayBuffer::obj_defineProperty,
ArrayBuffer::obj_defineElement,
ArrayBuffer::obj_defineSpecial,
ArrayBuffer::obj_getGeneric,
ArrayBuffer::obj_getProperty,
ArrayBuffer::obj_getElement,
ArrayBuffer::obj_getElementIfPresent,
ArrayBuffer::obj_getSpecial,
ArrayBuffer::obj_setGeneric,
ArrayBuffer::obj_setProperty,
ArrayBuffer::obj_setElement,
ArrayBuffer::obj_setSpecial,
ArrayBuffer::obj_getGenericAttributes,
ArrayBuffer::obj_getPropertyAttributes,
ArrayBuffer::obj_getElementAttributes,
ArrayBuffer::obj_getSpecialAttributes,
ArrayBuffer::obj_setGenericAttributes,
ArrayBuffer::obj_setPropertyAttributes,
ArrayBuffer::obj_setElementAttributes,
ArrayBuffer::obj_setSpecialAttributes,
ArrayBuffer::obj_deleteProperty,
ArrayBuffer::obj_deleteElement,
ArrayBuffer::obj_deleteSpecial,
ArrayBuffer::obj_enumerate,
ArrayBuffer::obj_typeOf,
ArrayBufferObject::obj_lookupGeneric,
ArrayBufferObject::obj_lookupProperty,
ArrayBufferObject::obj_lookupElement,
ArrayBufferObject::obj_lookupSpecial,
ArrayBufferObject::obj_defineGeneric,
ArrayBufferObject::obj_defineProperty,
ArrayBufferObject::obj_defineElement,
ArrayBufferObject::obj_defineSpecial,
ArrayBufferObject::obj_getGeneric,
ArrayBufferObject::obj_getProperty,
ArrayBufferObject::obj_getElement,
ArrayBufferObject::obj_getElementIfPresent,
ArrayBufferObject::obj_getSpecial,
ArrayBufferObject::obj_setGeneric,
ArrayBufferObject::obj_setProperty,
ArrayBufferObject::obj_setElement,
ArrayBufferObject::obj_setSpecial,
ArrayBufferObject::obj_getGenericAttributes,
ArrayBufferObject::obj_getPropertyAttributes,
ArrayBufferObject::obj_getElementAttributes,
ArrayBufferObject::obj_getSpecialAttributes,
ArrayBufferObject::obj_setGenericAttributes,
ArrayBufferObject::obj_setPropertyAttributes,
ArrayBufferObject::obj_setElementAttributes,
ArrayBufferObject::obj_setSpecialAttributes,
ArrayBufferObject::obj_deleteProperty,
ArrayBufferObject::obj_deleteElement,
ArrayBufferObject::obj_deleteSpecial,
ArrayBufferObject::obj_enumerate,
ArrayBufferObject::obj_typeOf,
NULL, /* thisObject */
NULL, /* clear */
}
};
JSPropertySpec ArrayBuffer::jsprops[] = {
JSPropertySpec ArrayBufferObject::jsprops[] = {
{ "byteLength",
-1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
ArrayBuffer::prop_getByteLength, JS_StrictPropertyStub },
ArrayBufferObject::prop_getByteLength, JS_StrictPropertyStub },
{0,0,0,0,0}
};
JSFunctionSpec ArrayBuffer::jsfuncs[] = {
JS_FN("slice", ArrayBuffer::fun_slice, 2, JSFUN_GENERIC_NATIVE),
JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
JS_FS_END
};
@ -2279,7 +2299,7 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32, uint32_t)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
#define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray) \
#define IMPL_TYPED_ARRAY_PROTO_CLASS(_typedArray) \
{ \
#_typedArray, \
JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) | \
@ -2362,7 +2382,7 @@ template<class ArrayType>
static inline JSObject *
InitTypedArrayClass(JSContext *cx, GlobalObject *global)
{
JSObject *proto = global->createBlankPrototype(cx, ArrayType::slowClass());
JSObject *proto = global->createBlankPrototype(cx, ArrayType::protoClass());
if (!proto)
return NULL;
@ -2418,27 +2438,27 @@ Class TypedArray::fastClasses[TYPE_MAX] = {
IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray)
};
Class TypedArray::slowClasses[TYPE_MAX] = {
IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array),
IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray)
Class TypedArray::protoClasses[TYPE_MAX] = {
IMPL_TYPED_ARRAY_PROTO_CLASS(Int8Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Int16Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Int32Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float32Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float64Array),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray)
};
static JSObject *
InitArrayBufferClass(JSContext *cx, GlobalObject *global)
{
JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBuffer::slowClass);
JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBufferObject::protoClass);
if (!arrayBufferProto)
return NULL;
JSFunction *ctor =
global->createConstructor(cx, ArrayBuffer::class_constructor,
global->createConstructor(cx, ArrayBufferObject::class_constructor,
CLASS_ATOM(cx, ArrayBuffer), 1);
if (!ctor)
return NULL;
@ -2446,7 +2466,7 @@ InitArrayBufferClass(JSContext *cx, GlobalObject *global)
if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
return NULL;
if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBuffer::jsprops, ArrayBuffer::jsfuncs))
if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBufferObject::jsprops, ArrayBufferObject::jsfuncs))
return NULL;
if (!DefineConstructorAndPrototype(cx, global, JSProto_ArrayBuffer, ctor, arrayBufferProto))
@ -2495,8 +2515,8 @@ js::IsFastTypedArrayClass(const Class *clasp)
static inline bool
IsSlowTypedArrayClass(const Class *clasp)
{
return &TypedArray::slowClasses[0] <= clasp &&
clasp < &TypedArray::slowClasses[TypedArray::TYPE_MAX];
return &TypedArray::protoClasses[0] <= clasp &&
clasp < &TypedArray::protoClasses[TypedArray::TYPE_MAX];
}
bool
@ -2526,22 +2546,21 @@ JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
JS_ASSERT(obj->isArrayBuffer());
return obj->arrayBufferByteLength();
return obj->asArrayBuffer().byteLength();
}
JS_FRIEND_API(uint8_t *)
JS_GetArrayBufferData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
JS_ASSERT(obj->isArrayBuffer());
return obj->arrayBufferDataOffset();
return obj->asArrayBuffer().dataPointer();
}
JS_FRIEND_API(JSObject *)
JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
{
return ArrayBuffer::create(cx, nbytes);
JS_ASSERT(nbytes <= INT32_MAX);
return ArrayBufferObject::create(cx, nbytes);
}
JS_FRIEND_API(uint32_t)

View File

@ -50,15 +50,15 @@ typedef struct JSProperty JSProperty;
namespace js {
/*
* ArrayBuffer
* ArrayBufferObject
*
* This class holds the underlying raw buffer that the TypedArray
* subclasses access. It can be created explicitly and passed to a
* TypedArray subclass, or can be created implicitly by constructing a
* TypedArray with a size.
* This class holds the underlying raw buffer that the various ArrayBufferView
* subclasses (DataView and the TypedArrays) access. It can be created
* explicitly and passed to an ArrayBufferView subclass, or can be created
* implicitly by constructing a TypedArray with a size.
*/
struct ArrayBuffer {
static Class slowClass;
struct ArrayBufferObject : public JSObject {
static Class protoClass;
static JSPropertySpec jsprops[];
static JSFunctionSpec jsfuncs[];
@ -68,17 +68,11 @@ struct ArrayBuffer {
static JSBool class_constructor(JSContext *cx, unsigned argc, Value *vp);
static JSObject *create(JSContext *cx, int32_t nbytes, uint8_t *contents = NULL);
static JSObject *create(JSContext *cx, uint32_t nbytes, uint8_t *contents = NULL);
static JSObject *createSlice(JSContext *cx, JSObject *arrayBuffer,
static JSObject *createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
uint32_t begin, uint32_t end);
ArrayBuffer()
{
}
~ArrayBuffer();
static void
obj_trace(JSTracer *trc, JSObject *obj);
@ -167,6 +161,19 @@ struct ArrayBuffer {
static JSObject *
getArrayBuffer(JSObject *obj);
bool
allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
inline uint32_t byteLength() const;
inline uint8_t * dataPointer() const;
/*
* Check if the arrayBuffer contains any data. This will return false for
* ArrayBuffer.prototype and neutered ArrayBuffers.
*/
inline bool hasData() const;
};
/*
@ -211,9 +218,9 @@ struct TypedArray {
// and MUST NOT be used to construct new objects.
static Class fastClasses[TYPE_MAX];
// These are the slow/original classes, used
// These are the proto/original classes, used
// fo constructing new objects
static Class slowClasses[TYPE_MAX];
static Class protoClasses[TYPE_MAX];
static JSPropertySpec jsprops[];
@ -247,7 +254,7 @@ struct TypedArray {
static uint32_t getByteOffset(JSObject *obj);
static uint32_t getByteLength(JSObject *obj);
static uint32_t getType(JSObject *obj);
static JSObject * getBuffer(JSObject *obj);
static ArrayBufferObject * getBuffer(JSObject *obj);
static void * getDataOffset(JSObject *obj);
public:

View File

@ -44,20 +44,33 @@
#include "jsobj.h"
inline uint32_t
JSObject::arrayBufferByteLength()
js::ArrayBufferObject::byteLength() const
{
JS_ASSERT(isArrayBuffer());
return getElementsHeader()->length;
}
inline uint8_t *
JSObject::arrayBufferDataOffset()
js::ArrayBufferObject::dataPointer() const
{
return (uint8_t *) elements;
}
inline js::ArrayBufferObject &
JSObject::asArrayBuffer()
{
JS_ASSERT(isArrayBuffer());
return *static_cast<js::ArrayBufferObject *>(this);
}
namespace js {
inline bool
ArrayBufferObject::hasData() const
{
return getClass() == &ArrayBufferClass;
}
static inline int32_t
ClampIntForUint8Array(int32_t x)
{
@ -92,10 +105,10 @@ TypedArray::getType(JSObject *obj) {
return obj->getFixedSlot(FIELD_TYPE).toInt32();
}
inline JSObject *
inline ArrayBufferObject *
TypedArray::getBuffer(JSObject *obj) {
JS_ASSERT(IsFastOrSlowTypedArray(obj));
return &obj->getFixedSlot(FIELD_BUFFER).toObject();
return &obj->getFixedSlot(FIELD_BUFFER).toObject().asArrayBuffer();
}
inline void *
@ -104,5 +117,6 @@ TypedArray::getDataOffset(JSObject *obj) {
return (void *)obj->getPrivate(NUM_FIXED_SLOTS);
}
}
} /* namespace js */
#endif /* jstypedarrayinlines_h */

View File

@ -570,10 +570,12 @@ ElementsHeader::asArrayBufferElements()
* pointing to the beginning of that array (the end of this structure).
* See below for usage of this structure.
*/
class ArrayBufferObject;
class ObjectElements
{
friend struct ::JSObject;
friend class ObjectImpl;
friend struct js::ArrayBufferObject;
/* Number of allocated slots. */
uint32_t capacity;