Backed out changeset e35851f07b67 (bug 987508) for non-unified bustage.

This commit is contained in:
Ryan VanderMeulen 2014-04-07 15:49:48 -04:00
parent 80d8facaf9
commit 6ba3302194
13 changed files with 118 additions and 241 deletions

View File

@ -197,7 +197,7 @@ StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
new ThreadSharedFloatArrayBufferList(aJSArrays.Length());
for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
JS::Rooted<JSObject*> arrayBuffer(aJSContext,
JS_GetArrayBufferViewBuffer(aJSContext, aJSArrays[i]));
JS_GetArrayBufferViewBuffer(aJSArrays[i]));
uint8_t* stolenData = arrayBuffer
? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
: nullptr;

View File

@ -365,15 +365,6 @@ GetObjectAllocKindForCopy(JSRuntime *rt, JSObject *obj)
if (obj->is<JSFunction>())
return obj->as<JSFunction>().getAllocKind();
/*
* Typed arrays in the nursery may have a lazily allocated buffer, make
* sure there is room for the array's fixed data when moving the array.
*/
if (obj->is<TypedArrayObject>() && !obj->as<TypedArrayObject>().buffer()) {
size_t nbytes = obj->as<TypedArrayObject>().byteLength();
return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
}
AllocKind kind = GetGCObjectFixedSlotsKind(obj->numFixedSlots());
JS_ASSERT(!IsBackgroundFinalized(kind));
JS_ASSERT(CanBeFinalizedInBackground(kind, obj->getClass()));
@ -570,9 +561,6 @@ js::Nursery::moveObjectToTenured(JSObject *dst, JSObject *src, AllocKind dstKind
tenuredSize += moveSlotsToTenured(dst, src, dstKind);
tenuredSize += moveElementsToTenured(dst, src, dstKind);
if (src->is<TypedArrayObject>())
dst->setPrivate(dst->fixedData(TypedArrayObject::FIXED_DATA_START));
/* The shape's list head may point into the old object. */
if (&src->shape_ == dst->shape_->listp)
dst->shape_->listp = &dst->shape_;

View File

@ -109,7 +109,7 @@ TestArrayFromBuffer(JSContext *cx)
CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer);
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(array), (JSObject*) buffer);
Element *data;
CHECK(data = GetData(array));

View File

@ -1432,7 +1432,7 @@ JS_GetArrayBufferViewData(JSObject *obj);
* object that would return true for JS_IsArrayBufferViewObject().
*/
extern JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj);
JS_GetArrayBufferViewBuffer(JSObject *obj);
/*
* Set an ArrayBuffer's length to 0 and neuter all of its views.

View File

@ -1253,12 +1253,17 @@ NewObject(ExclusiveContext *cx, types::TypeObject *type_, JSObject *parent, gc::
if (!NewObjectMetadata(cx, &metadata))
return nullptr;
// For objects which can have fixed data following the object, only use
// enough fixed slots to cover the number of reserved slots in the object,
// regardless of the allocation kind specified.
size_t nfixed = ClassCanHaveFixedData(clasp)
? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
: GetGCKindSlots(kind, clasp);
// Normally, the number of fixed slots given an object is the maximum
// permitted for its size class. For array buffers we only use enough to
// cover the class reservd slots, so that the remaining space in the
// object's allocation is available for the buffer's data.
size_t nfixed;
if (clasp == &ArrayBufferObject::class_) {
JS_STATIC_ASSERT(ArrayBufferObject::RESERVED_SLOTS == 4);
nfixed = ArrayBufferObject::RESERVED_SLOTS;
} else {
nfixed = GetGCKindSlots(kind, clasp);
}
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto(),
parent, metadata, nfixed));

View File

@ -475,8 +475,7 @@ JSObject::setProto(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto,
return SetClassAndProto(cx, obj, obj->getClass(), proto, succeeded);
}
inline bool
JSObject::isVarObj()
inline bool JSObject::isVarObj()
{
if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isVarObj();
@ -496,7 +495,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
JS_ASSERT(shape && type);
JS_ASSERT(type->clasp() == shape->getObjectClass());
JS_ASSERT(type->clasp() != &js::ArrayObject::class_);
JS_ASSERT_IF(!ClassCanHaveFixedData(type->clasp()),
JS_ASSERT_IF(type->clasp() != &js::ArrayBufferObject::class_,
js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);

View File

@ -631,7 +631,7 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, void *data /* = nullpt
if (data) {
obj->initialize(nbytes, data, OwnsData);
} else {
void *data = obj->fixedData(reservedSlots);
void *data = &obj->fixedSlots()[reservedSlots];
memset(data, 0, nbytes);
obj->initialize(nbytes, data, DoesntOwnData);
}
@ -929,17 +929,6 @@ ArrayBufferViewObject::neuter(void *newData)
as<TypedObject>().neuter(newData);
}
/* static */ ArrayBufferObject *
ArrayBufferViewObject::bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> thisObject)
{
if (thisObject->is<TypedArrayObject>()) {
Rooted<TypedArrayObject *> typedArray(cx, &thisObject->as<TypedArrayObject>());
if (!TypedArrayObject::ensureHasBuffer(cx, typedArray))
return nullptr;
}
return &thisObject->getFixedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObject>();
}
/* JS Friend API */
JS_FRIEND_API(bool)
@ -1058,13 +1047,12 @@ JS_GetArrayBufferViewData(JSObject *obj)
}
JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj)
JS_GetArrayBufferViewBuffer(JSObject *obj)
{
obj = CheckedUnwrap(obj);
if (!obj)
return nullptr;
Rooted<ArrayBufferViewObject *> viewObject(cx, &obj->as<ArrayBufferViewObject>());
return ArrayBufferViewObject::bufferObject(cx, viewObject);
return obj->as<ArrayBufferViewObject>().bufferObject();
}
JS_FRIEND_API(uint32_t)

View File

@ -240,7 +240,9 @@ class ArrayBufferViewObject : public JSObject
static const size_t NEXT_VIEW_SLOT = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
public:
static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj);
JSObject *bufferObject() const {
return &getFixedSlot(BUFFER_SLOT).toObject();
}
ArrayBufferViewObject *nextView() const {
return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());

View File

@ -13,12 +13,9 @@
#include "jsproxy.h"
#include "vm/ProxyObject.h"
#include "vm/TypedArrayObject.h"
namespace js {
/* static */ inline bool
ObjectImpl::isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible)
js::ObjectImpl::isExtensible(ExclusiveContext *cx, js::Handle<ObjectImpl*> obj, bool *extensible)
{
if (obj->asObjectPtr()->is<ProxyObject>()) {
if (!cx->shouldBeJSContext())
@ -32,24 +29,4 @@ ObjectImpl::isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *ex
return true;
}
inline bool
ClassCanHaveFixedData(const Class *clasp)
{
// Normally, the number of fixed slots given an object is the maximum
// permitted for its size class. For array buffers and typed arrays we only
// use enough to cover the class reserved slots, so that the remaining
// space in the object's allocation is available for the buffer's data.
return clasp == &ArrayBufferObject::class_ || IsTypedArrayClass(clasp);
}
inline void *
ObjectImpl::fixedData(size_t nslots) const
{
JS_ASSERT(ClassCanHaveFixedData(getClass()));
JS_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
return &fixedSlots()[nslots];
}
} // namespace js
#endif /* vm_ObjectImpl_inl_h */

View File

@ -94,12 +94,13 @@ ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
unsigned attrs, HandleValue value, bool setterIsStrict);
/*
* Elements header used for all objects. The elements component of such objects
* offers an efficient representation for all or some of the indexed properties
* of the object, using a flat array of Values rather than a shape hierarchy
* stored in the object's slots. This structure is immediately followed by an
* array of elements, with the elements member in an object pointing to the
* beginning of that array (the end of this structure).
* Elements header used for all objects other than non-native objects (except
* for ArrayBufferObjects!!!) and typed arrays. The elements component of such
* objects offers an efficient representation for all or some of the indexed
* properties of the object, using a flat array of Values rather than a shape
* hierarchy stored in the object's slots. This structure is immediately
* followed by an array of elements, with the elements member in an object
* pointing to the beginning of that array (the end of this structure).
* See below for usage of this structure.
*
* The sets of properties represented by an object's elements and slots
@ -148,14 +149,14 @@ ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
* value less than or equal to both the object's length and the object's
* capacity.
*
* There is flexibility in exactly the value the initialized length must hold,
* e.g. if an array has length 5, capacity 10, completely empty, it is valid
* for the initialized length to be any value between zero and 5, as long as
* the in memory values below the initialized length have been initialized with
* a hole value. However, in such cases we want to keep the initialized length
* as small as possible: if the object is known to have no hole values below
* its initialized length, then it is "packed" and can be accessed much faster
* by JIT code.
* With inference enabled, there is flexibility in exactly the value the
* initialized length must hold, e.g. if an array has length 5, capacity 10,
* completely empty, it is valid for the initialized length to be any value
* between zero and 5, as long as the in memory values below the initialized
* length have been initialized with a hole value. However, in such cases we
* want to keep the initialized length as small as possible: if the object is
* known to have no hole values below its initialized length, then it is
* "packed" and can be accessed much faster by JIT code.
*
* Elements do not track property creation order, so enumerating the elements
* of an object does not necessarily visit indexes in the order they were
@ -287,7 +288,7 @@ IsObjectValueInCompartment(js::Value v, JSCompartment *comp);
* variable-sized array of values for inline storage, which may be used by
* either properties of native objects (fixed slots), by elements (fixed
* elements), or by other data for certain kinds of objects, such as
* ArrayBufferObjects and TypedArrayObjects.
* ArrayBufferObjects.
*
* Two native objects with the same shape are guaranteed to have the same
* number of fixed slots.
@ -826,13 +827,6 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
return elements == emptyObjectElements;
}
/*
* Get a pointer to the unused data in the object's allocation immediately
* following this object, for use with objects which allocate a larger size
* class than they need and store non-elements data inline.
*/
inline void *fixedData(size_t nslots) const;
/* GC support. */
static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }

View File

@ -813,10 +813,6 @@ bool
JSStructuredCloneWriter::writeTypedArray(HandleObject obj)
{
Rooted<TypedArrayObject*> tarr(context(), &obj->as<TypedArrayObject>());
if (!TypedArrayObject::ensureHasBuffer(context(), tarr))
return false;
if (!out.writePair(SCTAG_TYPED_ARRAY_OBJECT, tarr->length()))
return false;
uint64_t type = tarr->type();

View File

@ -106,25 +106,6 @@ TypedArrayObject::sharedBuffer() const
return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<SharedArrayBufferObject>();
}
/* static */ bool
TypedArrayObject::ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray)
{
if (tarray->buffer())
return true;
Rooted<ArrayBufferObject *> buffer(cx, ArrayBufferObject::create(cx, tarray->byteLength()));
if (!buffer)
return false;
buffer->addView(tarray);
memcpy(buffer->dataPointer(), tarray->viewData(), tarray->byteLength());
InitArrayBufferViewDataPointer(tarray, buffer, 0);
tarray->setSlot(BUFFER_SLOT, ObjectValue(*buffer));
return true;
}
/* static */ int
TypedArrayObject::lengthOffset()
{
@ -206,13 +187,13 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return &TypedArrayObject::protoClasses[ArrayTypeID()];
}
static inline const Class *instanceClass()
static inline const Class *fastClass()
{
return &TypedArrayObject::classes[ArrayTypeID()];
}
static bool is(HandleValue v) {
return v.isObject() && v.toObject().hasClass(instanceClass());
return v.isObject() && v.toObject().hasClass(fastClass());
}
static void
@ -241,11 +222,11 @@ class TypedArrayObjectTemplate : public TypedArrayObject
}
static TypedArrayObject *
makeProtoInstance(JSContext *cx, HandleObject proto, AllocKind allocKind)
makeProtoInstance(JSContext *cx, HandleObject proto)
{
JS_ASSERT(proto);
RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind));
RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass()));
if (!obj)
return nullptr;
@ -258,19 +239,19 @@ class TypedArrayObjectTemplate : public TypedArrayObject
}
static TypedArrayObject *
makeTypedInstance(JSContext *cx, uint32_t len, AllocKind allocKind)
makeTypedInstance(JSContext *cx, uint32_t len)
{
if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_TYPE_BYTE_LENGTH) {
return &NewBuiltinClassInstance(cx, instanceClass(), allocKind,
return &NewBuiltinClassInstance(cx, fastClass(),
SingletonObject)->as<TypedArrayObject>();
}
jsbytecode *pc;
RootedScript script(cx, cx->currentScript(&pc));
NewObjectKind newKind = script
? UseNewTypeForInitializer(script, pc, instanceClass())
? UseNewTypeForInitializer(script, pc, fastClass())
: GenericObject;
RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind, newKind));
RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass(), newKind));
if (!obj)
return nullptr;
@ -283,61 +264,56 @@ class TypedArrayObjectTemplate : public TypedArrayObject
}
static JSObject *
makeInstance(JSContext *cx, Handle<ArrayBufferObject *> buffer, uint32_t byteOffset, uint32_t len,
makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len,
HandleObject proto)
{
JS_ASSERT_IF(!buffer, byteOffset == 0);
gc::AllocKind allocKind = buffer
? GetGCObjectKind(instanceClass())
: AllocKindForLazyBuffer(len * sizeof(NativeType));
Rooted<TypedArrayObject*> obj(cx);
if (proto)
obj = makeProtoInstance(cx, proto, allocKind);
obj = makeProtoInstance(cx, proto);
else
obj = makeTypedInstance(cx, len, allocKind);
obj = makeTypedInstance(cx, len);
if (!obj)
return nullptr;
JS_ASSERT_IF(obj->isTenured(),
obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
obj->setSlot(TYPE_SLOT, Int32Value(ArrayTypeID()));
obj->setSlot(BUFFER_SLOT, ObjectOrNullValue(buffer));
obj->setSlot(BUFFER_SLOT, ObjectValue(*bufobj));
if (buffer) {
InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
} else {
void *data = obj->fixedData(FIXED_DATA_START);
obj->initPrivate(data);
memset(data, 0, len * sizeof(NativeType));
}
Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
obj->setSlot(LENGTH_SLOT, Int32Value(len));
obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType)));
obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
obj->getProto(), obj->getParent(), obj->getMetadata(),
gc::FINALIZE_OBJECT8_BACKGROUND);
if (!empty)
return nullptr;
obj->setLastPropertyInfallible(empty);
#ifdef DEBUG
if (buffer) {
uint32_t arrayByteLength = obj->byteLength();
uint32_t arrayByteOffset = obj->byteOffset();
uint32_t bufferByteLength = buffer->byteLength();
JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
JS_ASSERT(arrayByteOffset <= bufferByteLength);
}
uint32_t bufferByteLength = buffer->byteLength();
uint32_t arrayByteLength = obj->byteLength();
uint32_t arrayByteOffset = obj->byteOffset();
JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
JS_ASSERT(arrayByteOffset <= bufferByteLength);
// Verify that the private slot is at the expected place
JS_ASSERT(obj->numFixedSlots() == DATA_SLOT);
#endif
if (buffer)
buffer->addView(obj);
buffer->addView(obj);
return obj;
}
static JSObject *
makeInstance(JSContext *cx, Handle<ArrayBufferObject *> bufobj, uint32_t byteOffset, uint32_t len)
makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len)
{
RootedObject nullproto(cx, nullptr);
return makeInstance(cx, bufobj, byteOffset, len, nullproto);
@ -352,7 +328,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
static bool
class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
/* N.B. this is a constructor for protoClass, not instanceClass! */
/* N.B. this is a constructor for protoClass, not fastClass! */
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *obj = create(cx, args);
if (!obj)
@ -420,7 +396,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
}
static bool IsThisClass(HandleValue v) {
return v.isObject() && v.toObject().hasClass(instanceClass());
return v.isObject() && v.toObject().hasClass(fastClass());
}
template<Value ValueGetter(TypedArrayObject *tarr)>
@ -444,36 +420,16 @@ class TypedArrayObjectTemplate : public TypedArrayObject
ThisTypedArrayObject::GetterImpl<ValueGetter> >(cx, args);
}
static bool
BufferGetterImpl(JSContext *cx, CallArgs args)
{
JS_ASSERT(IsThisClass(args.thisv()));
Rooted<TypedArrayObject *> tarray(cx, &args.thisv().toObject().as<TypedArrayObject>());
if (!ensureHasBuffer(cx, tarray))
return false;
args.rval().set(bufferValue(tarray));
return true;
}
// BufferGetter is a function that lazily constructs the array buffer for a
// typed array before fetching it.
static bool
BufferGetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<ThisTypedArrayObject::IsThisClass,
ThisTypedArrayObject::BufferGetterImpl>(cx, args);
}
// Define an accessor for a read-only property that invokes a native getter
template<Value ValueGetter(TypedArrayObject *tarr)>
static bool
DefineGetter(JSContext *cx, HandleObject proto, PropertyName *name, Native native)
DefineGetter(JSContext *cx, PropertyName *name, HandleObject proto)
{
RootedId id(cx, NameToId(name));
unsigned flags = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
JSObject *getter = NewFunction(cx, NullPtr(), native, 0,
JSObject *getter = NewFunction(cx, NullPtr(), Getter<ValueGetter>, 0,
JSFunction::NATIVE_FUN, global, NullPtr());
if (!getter)
return false;
@ -486,16 +442,16 @@ class TypedArrayObjectTemplate : public TypedArrayObject
static
bool defineGetters(JSContext *cx, HandleObject proto)
{
if (!DefineGetter(cx, proto, cx->names().length, Getter<lengthValue>))
if (!DefineGetter<lengthValue>(cx, cx->names().length, proto))
return false;
if (!DefineGetter(cx, proto, cx->names().buffer, BufferGetter))
if (!DefineGetter<bufferValue>(cx, cx->names().buffer, proto))
return false;
if (!DefineGetter(cx, proto, cx->names().byteLength, Getter<byteLengthValue>))
if (!DefineGetter<byteLengthValue>(cx, cx->names().byteLength, proto))
return false;
if (!DefineGetter(cx, proto, cx->names().byteOffset, Getter<byteOffsetValue>))
if (!DefineGetter<byteOffsetValue>(cx, cx->names().byteOffset, proto))
return false;
return true;
@ -715,7 +671,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
*/
Rooted<JSObject*> proto(cx);
if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto))
if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(fastClass()), &proto))
return nullptr;
InvokeArgs args(cx);
@ -739,17 +695,17 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return nullptr; // must be arrayBuffer
}
Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
ArrayBufferObject &buffer = AsArrayBuffer(bufobj);
if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) {
if (byteOffset > buffer.byteLength() || byteOffset % sizeof(NativeType) != 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return nullptr; // invalid byteOffset
}
uint32_t len;
if (lengthInt == -1) {
len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
if (len * sizeof(NativeType) != buffer->byteLength() - byteOffset) {
len = (buffer.byteLength() - byteOffset) / sizeof(NativeType);
if (len * sizeof(NativeType) != buffer.byteLength() - byteOffset) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_BAD_ARGS);
return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
@ -765,41 +721,19 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return nullptr; // overflow when calculating byteOffset + len * sizeof(NativeType)
}
if (arrayByteLength + byteOffset > buffer->byteLength()) {
if (arrayByteLength + byteOffset > buffer.byteLength()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return nullptr; // byteOffset + len is too big for the arraybuffer
}
return makeInstance(cx, buffer, byteOffset, len, proto);
}
static bool
maybeCreateArrayBuffer(JSContext *cx, uint32_t nelements, MutableHandle<ArrayBufferObject *> buffer)
{
// Make sure that array elements evenly divide into the inline buffer's
// size, for the test below.
JS_STATIC_ASSERT((INLINE_BUFFER_LIMIT / sizeof(NativeType)) * sizeof(NativeType) == INLINE_BUFFER_LIMIT);
if (nelements <= INLINE_BUFFER_LIMIT / sizeof(NativeType)) {
// The array's data can be inline, and the buffer created lazily.
return true;
}
if (nelements >= INT32_MAX / sizeof(NativeType)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_NEED_DIET, "size and count");
return false;
}
buffer.set(ArrayBufferObject::create(cx, nelements * sizeof(NativeType)));
return !!buffer;
return makeInstance(cx, bufobj, byteOffset, len, proto);
}
static JSObject *
fromLength(JSContext *cx, uint32_t nelements)
{
Rooted<ArrayBufferObject *> buffer(cx);
if (!maybeCreateArrayBuffer(cx, nelements, &buffer))
RootedObject buffer(cx, createBufferWithSizeAndCount(cx, nelements));
if (!buffer)
return nullptr;
return makeInstance(cx, buffer, 0, nelements);
}
@ -814,11 +748,11 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return nullptr;
}
Rooted<ArrayBufferObject *> buffer(cx);
if (!maybeCreateArrayBuffer(cx, len, &buffer))
RootedObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
if (!bufobj)
return nullptr;
RootedObject obj(cx, makeInstance(cx, buffer, 0, len));
RootedObject obj(cx, makeInstance(cx, bufobj, 0, len));
if (!obj || !copyFromArray(cx, obj, other, len))
return nullptr;
return obj;
@ -847,10 +781,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
JS_ASSERT(begin <= tarray->length());
JS_ASSERT(end <= tarray->length());
if (!ensureHasBuffer(cx, tarray))
return nullptr;
Rooted<ArrayBufferObject *> bufobj(cx, tarray->buffer());
RootedObject bufobj(cx, tarray->buffer());
JS_ASSERT(bufobj);
JS_ASSERT(begin <= end);
@ -1134,6 +1065,20 @@ class TypedArrayObjectTemplate : public TypedArrayObject
js_free(srcbuf);
return true;
}
static JSObject *
createBufferWithSizeAndCount(JSContext *cx, uint32_t count)
{
size_t size = sizeof(NativeType);
if (size != 0 && count >= INT32_MAX / size) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_NEED_DIET, "size and count");
return nullptr;
}
uint32_t bytelen = size * count;
return ArrayBufferObject::create(cx, bytelen);
}
};
class Int8ArrayObject : public TypedArrayObjectTemplate<int8_t> {

View File

@ -40,22 +40,6 @@ class TypedArrayObject : public ArrayBufferViewObject
static const Class classes[ScalarTypeDescr::TYPE_MAX];
static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
static const size_t FIXED_DATA_START = DATA_SLOT + 1;
// For typed arrays which can store their data inline, the array buffer
// object is created lazily.
static const uint32_t INLINE_BUFFER_LIMIT =
(JSObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
static gc::AllocKind
AllocKindForLazyBuffer(size_t nbytes)
{
JS_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
int dataSlots = (nbytes - 1) / sizeof(Value) + 1;
JS_ASSERT(int(nbytes) <= dataSlots * int(sizeof(Value)));
return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
}
static Value bufferValue(TypedArrayObject *tarr) {
return tarr->getFixedSlot(BUFFER_SLOT);
}
@ -69,16 +53,11 @@ class TypedArrayObject : public ArrayBufferViewObject
return tarr->getFixedSlot(LENGTH_SLOT);
}
static bool
ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray);
ArrayBufferObject *sharedBuffer() const;
ArrayBufferObject *buffer() const {
JSObject *obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
if (!obj)
return nullptr;
if (obj->is<ArrayBufferObject>())
return &obj->as<ArrayBufferObject>();
JSObject &obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObject();
if (obj.is<ArrayBufferObject>())
return &obj.as<ArrayBufferObject>();
return sharedBuffer();
}
uint32_t byteOffset() const {
@ -249,10 +228,6 @@ class DataViewObject : public ArrayBufferViewObject
return v;
}
static Value bufferValue(DataViewObject *view) {
return view->getReservedSlot(BUFFER_SLOT);
}
uint32_t byteOffset() const {
return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
}
@ -261,8 +236,16 @@ class DataViewObject : public ArrayBufferViewObject
return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
}
bool hasBuffer() const {
return getReservedSlot(BUFFER_SLOT).isObject();
}
ArrayBufferObject &arrayBuffer() const {
return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
return getReservedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObject>();
}
static Value bufferValue(DataViewObject *view) {
return view->hasBuffer() ? ObjectValue(view->arrayBuffer()) : UndefinedValue();
}
void *dataPointer() const {