mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 789589 - Implement JS_NewDataView, r=Waldo
--HG-- extra : commitid : b5iH1lEe6N extra : rebase_source : 81579a6e32a33acb08850dd7b8d6d3b900e02b3b
This commit is contained in:
parent
8586708ac6
commit
713936e41b
@ -86,23 +86,10 @@ BEGIN_TEST(testArrayBufferView_type)
|
||||
static JSObject*
|
||||
CreateDataView(JSContext* cx)
|
||||
{
|
||||
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
if (!global)
|
||||
JS::Rooted<JSObject*> buffer(cx, JS_NewArrayBuffer(cx, 8));
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
|
||||
static const char code[] = "new DataView(new ArrayBuffer(8))";
|
||||
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
JS::CompileOptions opts(cx);
|
||||
if (!JS::Evaluate(cx, opts.setFileAndLine(__FILE__, __LINE__),
|
||||
code, strlen(code), &val))
|
||||
return nullptr;
|
||||
|
||||
JS::Rooted<JSObject*> dv(cx, &val.toObject());
|
||||
if (!JS_IsDataViewObject(dv))
|
||||
return nullptr;
|
||||
|
||||
return dv;
|
||||
return JS_NewDataView(cx, buffer, 0, 8);
|
||||
}
|
||||
|
||||
template<JSObject * CreateTypedArray(JSContext* cx, uint32_t length),
|
||||
@ -141,6 +128,42 @@ bool TestViewType(JSContext* cx)
|
||||
CHECK(len == ExpectedLength);
|
||||
}
|
||||
|
||||
JS::CompartmentOptions options;
|
||||
JS::RootedObject otherGlobal(cx, JS_NewGlobalObject(cx, basicGlobalClass(), nullptr, JS::DontFireOnNewGlobalHook, options));
|
||||
CHECK(otherGlobal);
|
||||
|
||||
JS::Rooted<JSObject*> buffer(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, otherGlobal);
|
||||
buffer = JS_NewArrayBuffer(cx, 8);
|
||||
CHECK(buffer);
|
||||
CHECK(buffer->as<ArrayBufferObject>().byteLength() == 8);
|
||||
}
|
||||
CHECK(buffer->compartment() == otherGlobal->compartment());
|
||||
CHECK(JS_WrapObject(cx, &buffer));
|
||||
CHECK(buffer->compartment() == global->compartment());
|
||||
|
||||
JS::Rooted<JSObject*> dataview(cx, JS_NewDataView(cx, buffer, 4, 4));
|
||||
CHECK(dataview);
|
||||
CHECK(dataview->is<ProxyObject>());
|
||||
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
|
||||
val = ObjectValue(*dataview);
|
||||
CHECK(JS_SetProperty(cx, global, "view", val));
|
||||
|
||||
EVAL("view.buffer", &val);
|
||||
CHECK(val.toObject().is<ProxyObject>());
|
||||
|
||||
CHECK(dataview->compartment() == global->compartment());
|
||||
JS::Rooted<JSObject*> otherView(cx, js::UncheckedUnwrap(dataview));
|
||||
CHECK(otherView->compartment() == otherGlobal->compartment());
|
||||
JS::Rooted<JSObject*> otherBuffer(cx, js::UncheckedUnwrap(&val.toObject()));
|
||||
CHECK(otherBuffer->compartment() == otherGlobal->compartment());
|
||||
|
||||
EVAL("Object.getPrototypeOf(view) === DataView.prototype", &val);
|
||||
CHECK(val.toBoolean() == true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2127,6 +2127,16 @@ JS_IsNeuteredArrayBufferObject(JSObject* obj);
|
||||
JS_FRIEND_API(bool)
|
||||
JS_IsDataViewObject(JSObject* obj);
|
||||
|
||||
/*
|
||||
* Create a new DataView using the given ArrayBuffer for storage. The given
|
||||
* buffer must be an ArrayBuffer (or a cross-compartment wrapper of an
|
||||
* ArrayBuffer), and the offset and length must fit within the bounds of the
|
||||
* arrayBuffer. Currently, nullptr will be returned and an exception will be
|
||||
* thrown if these conditions do not hold, but do not depend on that behavior.
|
||||
*/
|
||||
JS_FRIEND_API(JSObject*)
|
||||
JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength);
|
||||
|
||||
/*
|
||||
* Return the byte offset of a data view into its array buffer. |obj| must be a
|
||||
* DataView.
|
||||
|
@ -481,8 +481,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
public:
|
||||
static JSObject*
|
||||
fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt) {
|
||||
RootedObject proto(cx, nullptr);
|
||||
return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, proto);
|
||||
return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, nullptr);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
@ -969,17 +968,11 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
{
|
||||
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
||||
MOZ_ASSERT(byteLength <= INT32_MAX);
|
||||
MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
|
||||
|
||||
RootedObject proto(cx, protoArg);
|
||||
RootedObject obj(cx);
|
||||
|
||||
// This is overflow-safe: 2 * INT32_MAX is still a valid uint32_t.
|
||||
if (byteOffset + byteLength > arrayBuffer->byteLength()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
|
||||
obj = NewBuiltinClassInstance(cx, &class_, newKind);
|
||||
if (!obj)
|
||||
@ -1002,12 +995,17 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
}
|
||||
}
|
||||
|
||||
// Caller should have established these preconditions, and no
|
||||
// (non-self-hosted) JS code has had an opportunity to run so nothing can
|
||||
// have invalidated them.
|
||||
MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
|
||||
MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
||||
|
||||
DataViewObject& dvobj = obj->as<DataViewObject>();
|
||||
dvobj.setFixedSlot(TypedArrayLayout::BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||
dvobj.setFixedSlot(TypedArrayLayout::LENGTH_SLOT, Int32Value(byteLength));
|
||||
dvobj.setFixedSlot(TypedArrayLayout::BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||
dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset);
|
||||
MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
||||
|
||||
// Include a barrier if the data view's data pointer is in the nursery, as
|
||||
// is done for typed arrays.
|
||||
@ -1033,9 +1031,8 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
uint32_t bufferLength = buffer->byteLength();
|
||||
uint32_t byteOffset = 0;
|
||||
uint32_t byteLength = bufferLength;
|
||||
uint32_t byteLength = buffer->byteLength();
|
||||
|
||||
if (args.length() > 1) {
|
||||
if (!ToUint32(cx, args[1], &byteOffset))
|
||||
@ -1055,6 +1052,8 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
uint32_t bufferLength = buffer->byteLength();
|
||||
|
||||
if (byteOffset > bufferLength) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
@ -1069,7 +1068,7 @@ DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args,
|
||||
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
||||
MOZ_ASSERT(byteLength <= INT32_MAX);
|
||||
|
||||
if (byteOffset + byteLength > bufferLength) {
|
||||
if (byteOffset + byteLength > buffer->byteLength()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return false;
|
||||
}
|
||||
@ -2348,3 +2347,27 @@ JS_GetDataViewByteLength(JSObject* obj)
|
||||
return 0;
|
||||
return obj->as<DataViewObject>().byteLength();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
JS_NewDataView(JSContext* cx, HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength)
|
||||
{
|
||||
ConstructArgs cargs(cx);
|
||||
if (!cargs.init(3))
|
||||
return nullptr;
|
||||
|
||||
RootedObject constructor(cx);
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewObject::class_);
|
||||
if (!GetBuiltinConstructor(cx, key, &constructor))
|
||||
return nullptr;
|
||||
|
||||
cargs[0].setObject(*arrayBuffer);
|
||||
cargs[1].setNumber(byteOffset);
|
||||
cargs[2].setInt32(byteLength);
|
||||
|
||||
RootedValue fun(cx, ObjectValue(*constructor));
|
||||
RootedValue rval(cx);
|
||||
if (!Construct(cx, fun, cargs, fun, &rval))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(rval.isObject());
|
||||
return &rval.toObject();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user