mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 575688 - Implement DataView from Typed Arrays spec. r=Waldo
--HG-- extra : rebase_source : b351000320c910c905be386cf71a9933cfe01a0f
This commit is contained in:
parent
7c9f81a176
commit
0aa674568a
@ -147,7 +147,7 @@ MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_ERR, "can't open {0}: {1}")
|
||||
MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
|
||||
MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
|
||||
MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE, 63, 0, JSEXN_INTERNALERR, "data are to big to encode")
|
||||
MSG_DEF(JSMSG_UNUSED64, 64, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 64, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
|
||||
MSG_DEF(JSMSG_UNUSED65, 65, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED66, 66, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED67, 67, 0, JSEXN_NONE, "")
|
||||
|
@ -1862,6 +1862,7 @@ static JSStdName standard_class_names[] = {
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
|
||||
TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(DataView), &DataViewClass},
|
||||
|
||||
{js_InitWeakMapClass, EAGER_ATOM_AND_CLASP(WeakMap)},
|
||||
{js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
|
||||
|
@ -3733,7 +3733,7 @@ struct JSClass {
|
||||
#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10)
|
||||
#define JSCLASS_CACHED_PROTO_WIDTH 6
|
||||
#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
|
||||
#define JSCLASS_HAS_CACHED_PROTO(key) ((key) << JSCLASS_CACHED_PROTO_SHIFT)
|
||||
#define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
|
||||
#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
|
||||
(((clasp)->flags \
|
||||
>> JSCLASS_CACHED_PROTO_SHIFT) \
|
||||
|
@ -973,6 +973,16 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes);
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsTypedArrayObject(JSObject *obj, JSContext *cx);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
|
||||
* return false if a security wrapper is encountered that denies the
|
||||
* unwrapping. If this test or one of the more specific tests succeeds, then it
|
||||
* is safe to call the various ArrayBufferView accessor JSAPI calls defined
|
||||
* below. cx MUST be non-NULL and valid.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
|
||||
|
||||
/*
|
||||
* Test for specific typed array types (ArrayBufferView subtypes)
|
||||
*/
|
||||
@ -1124,4 +1134,46 @@ JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx);
|
||||
extern JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
|
||||
* throw an exception if a security wrapper is encountered that denies the
|
||||
* operation.
|
||||
*/
|
||||
JS_FRIEND_API(JSBool)
|
||||
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
|
||||
|
||||
/*
|
||||
* Return the byte offset of a data view into its array buffer. |obj| must be a
|
||||
* DataView.
|
||||
*
|
||||
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
|
||||
* it would pass such a test: it is a data view or a wrapper of a data view,
|
||||
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx);
|
||||
|
||||
/*
|
||||
* Return the byte length of a data view.
|
||||
*
|
||||
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
|
||||
* it would pass such a test: it is a data view or a wrapper of a data view,
|
||||
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *cx);
|
||||
|
||||
/*
|
||||
* Return a pointer to the beginning of the data referenced by a DataView.
|
||||
*
|
||||
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
|
||||
* it would pass such a test: it is a data view or a wrapper of a data view,
|
||||
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
|
||||
* unable to assert when unwrapping should be disallowed.
|
||||
*/
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *cx);
|
||||
|
||||
#endif /* jsfriendapi_h___ */
|
||||
|
@ -1663,9 +1663,7 @@ GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, Value *vp
|
||||
NewPropertyDescriptorObject(cx, &desc, vp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp)
|
||||
{
|
||||
if (argc == 0) {
|
||||
@ -1689,6 +1687,8 @@ GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *me
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
static JSBool
|
||||
obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -233,6 +233,7 @@ extern Class ArrayBufferClass;
|
||||
extern Class BlockClass;
|
||||
extern Class BooleanClass;
|
||||
extern Class CallableObjectClass;
|
||||
extern Class DataViewClass;
|
||||
extern Class DateClass;
|
||||
extern Class ErrorClass;
|
||||
extern Class ElementIteratorClass;
|
||||
@ -259,6 +260,7 @@ class ArrayBufferObject;
|
||||
class BlockObject;
|
||||
class BooleanObject;
|
||||
class ClonedBlockObject;
|
||||
class DataViewObject;
|
||||
class DeclEnvObject;
|
||||
class ElementIteratorObject;
|
||||
class GlobalObject;
|
||||
@ -915,6 +917,7 @@ struct JSObject : public js::ObjectImpl
|
||||
/* Direct subtypes of JSObject: */
|
||||
inline bool isArguments() const;
|
||||
inline bool isArrayBuffer() const;
|
||||
inline bool isDataView() const;
|
||||
inline bool isDate() const;
|
||||
inline bool isElementIterator() const;
|
||||
inline bool isError() const;
|
||||
@ -967,6 +970,7 @@ struct JSObject : public js::ObjectImpl
|
||||
inline js::BooleanObject &asBoolean();
|
||||
inline js::CallObject &asCall();
|
||||
inline js::ClonedBlockObject &asClonedBlock();
|
||||
inline js::DataViewObject &asDataView();
|
||||
inline js::DeclEnvObject &asDeclEnv();
|
||||
inline js::GlobalObject &asGlobal();
|
||||
inline js::NestedScopeObject &asNestedScope();
|
||||
@ -1427,6 +1431,9 @@ InformalValueTypeName(const Value &v);
|
||||
inline void
|
||||
DestroyIdArray(FreeOp *fop, JSIdArray *ida);
|
||||
|
||||
extern bool
|
||||
GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp);
|
||||
|
||||
/* Helpers for throwing. These always return false. */
|
||||
extern bool
|
||||
Throw(JSContext *cx, jsid id, unsigned errorNumber);
|
||||
|
@ -790,6 +790,7 @@ inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); }
|
||||
inline bool JSObject::isBoolean() const { return hasClass(&js::BooleanClass); }
|
||||
inline bool JSObject::isCall() const { return hasClass(&js::CallClass); }
|
||||
inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
|
||||
inline bool JSObject::isDataView() const { return hasClass(&js::DataViewClass); }
|
||||
inline bool JSObject::isDate() const { return hasClass(&js::DateClass); }
|
||||
inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
|
||||
inline bool JSObject::isElementIterator() const { return hasClass(&js::ElementIteratorClass); }
|
||||
|
@ -94,6 +94,7 @@ JS_PROTO(AnyName, 35, js_InitNullClass)
|
||||
JS_PROTO(WeakMap, 36, js_InitWeakMapClass)
|
||||
JS_PROTO(Map, 37, js_InitMapClass)
|
||||
JS_PROTO(Set, 38, js_InitSetClass)
|
||||
JS_PROTO(DataView, 39, js_InitTypedArrayClasses)
|
||||
|
||||
#undef XML_INIT
|
||||
#undef NAMESPACE_INIT
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jsutil.h"
|
||||
#include "jshash.h"
|
||||
@ -51,6 +49,7 @@
|
||||
#include "jsatom.h"
|
||||
#include "jsbool.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jscpucfg.h"
|
||||
#include "jsversion.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsinterp.h"
|
||||
@ -60,6 +59,7 @@
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
|
||||
@ -817,6 +817,13 @@ TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsDataView(JSObject* obj)
|
||||
{
|
||||
JS_ASSERT(obj);
|
||||
return obj->isDataView();
|
||||
}
|
||||
|
||||
/*
|
||||
* For now (until slots directly hold data)
|
||||
* slots data element points to the JSObject representing the ArrayBuffer.
|
||||
@ -1190,7 +1197,32 @@ class TypedArrayTemplate
|
||||
}
|
||||
|
||||
static bool
|
||||
setElementTail(JSContext *cx, HandleObject tarray, uint32_t index, Value *vp, JSBool strict)
|
||||
toDoubleForTypedArray(JSContext *cx, Value *vp, double *d)
|
||||
{
|
||||
if (vp->isDouble()) {
|
||||
*d = vp->toDouble();
|
||||
} else if (vp->isNull()) {
|
||||
*d = 0.0;
|
||||
} else if (vp->isPrimitive()) {
|
||||
JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
|
||||
if (vp->isString()) {
|
||||
if (!ToNumber(cx, *vp, d))
|
||||
return false;
|
||||
} else if (vp->isUndefined()) {
|
||||
*d = js_NaN;
|
||||
} else {
|
||||
*d = double(vp->toBoolean());
|
||||
}
|
||||
} else {
|
||||
// non-primitive assignments become NaN or 0 (for float/int arrays)
|
||||
*d = js_NaN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
setElementTail(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp, JSBool strict)
|
||||
{
|
||||
JS_ASSERT(tarray);
|
||||
JS_ASSERT(index < getLength(tarray));
|
||||
@ -1201,23 +1233,8 @@ class TypedArrayTemplate
|
||||
}
|
||||
|
||||
double d;
|
||||
if (vp->isDouble()) {
|
||||
d = vp->toDouble();
|
||||
} else if (vp->isNull()) {
|
||||
d = 0.0;
|
||||
} else if (vp->isPrimitive()) {
|
||||
JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
|
||||
if (vp->isString()) {
|
||||
JS_ALWAYS_TRUE(ToNumber(cx, *vp, &d));
|
||||
} else if (vp->isUndefined()) {
|
||||
d = js_NaN;
|
||||
} else {
|
||||
d = double(vp->toBoolean());
|
||||
}
|
||||
} else {
|
||||
// non-primitive assignments become NaN or 0 (for float/int arrays)
|
||||
d = js_NaN;
|
||||
}
|
||||
if (!toDoubleForTypedArray(cx, vp, &d))
|
||||
return false;
|
||||
|
||||
// If the array is an integer array, we only handle up to
|
||||
// 32-bit ints from this point on. if we want to handle
|
||||
@ -1645,7 +1662,7 @@ class TypedArrayTemplate
|
||||
}
|
||||
|
||||
RootedVarObject arg0(cx, args[0].toObjectOrNull());
|
||||
RootedVarObject src(getTypedArray(arg0));
|
||||
RootedVarObject src(cx, getTypedArray(arg0));
|
||||
if (src) {
|
||||
if (getLength(src) > getLength(tarray) - offset) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||
@ -2151,10 +2168,552 @@ TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, ui
|
||||
* confuse the engine into interpreting a double-typed jsval as an
|
||||
* object-typed jsval.
|
||||
*/
|
||||
if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(val)))
|
||||
val = js_NaN;
|
||||
vp->setDouble(JS_CANONICALIZE_NAN(val));
|
||||
}
|
||||
|
||||
vp->setDouble(val);
|
||||
JSBool
|
||||
DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
JSObject *bufobj;
|
||||
if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
|
||||
return false;
|
||||
|
||||
if (!bufobj->isArrayBuffer()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE,
|
||||
"DataView", "ArrayBuffer", bufobj->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedVar<ArrayBufferObject*> buffer(cx, &bufobj->asArrayBuffer());
|
||||
uint32_t bufferLength = buffer->byteLength();
|
||||
uint32_t byteOffset = 0;
|
||||
uint32_t byteLength = bufferLength;
|
||||
|
||||
if (args.length() > 1) {
|
||||
if (!ToUint32(cx, args[1], &byteOffset))
|
||||
return false;
|
||||
if (byteOffset > INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.length() > 2) {
|
||||
if (!ToUint32(cx, args[2], &byteLength))
|
||||
return false;
|
||||
if (byteLength > INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (byteOffset > bufferLength) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return false;
|
||||
}
|
||||
|
||||
byteLength = bufferLength - byteOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/* The sum of these cannot overflow a uint32_t */
|
||||
JS_ASSERT(byteOffset <= INT32_MAX);
|
||||
JS_ASSERT(byteLength <= INT32_MAX);
|
||||
|
||||
if (byteOffset + byteLength > bufferLength) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *obj = DataViewObject::create(cx, byteOffset, byteLength, buffer);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isDataView());
|
||||
DataViewObject &view = obj->asDataView();
|
||||
if (view.hasBuffer())
|
||||
vp->setObject(view.arrayBuffer());
|
||||
else
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isDataView());
|
||||
DataViewObject &view = obj->asDataView();
|
||||
vp->setInt32(view.byteOffset());
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isDataView());
|
||||
DataViewObject &view = obj->asDataView();
|
||||
vp->setInt32(view.byteLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DataViewObject::getDataPointer(JSContext *cx, CallArgs args, size_t typeSize, uint8_t **data)
|
||||
{
|
||||
uint32_t offset;
|
||||
JS_ASSERT(args.length() > 0);
|
||||
if (!ToUint32(cx, args[0], &offset))
|
||||
return false;
|
||||
if (offset > UINT32_MAX - typeSize || offset + typeSize > byteLength()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = static_cast<uint8_t*>(dataPointer()) + offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
needToSwapBytes(bool littleEndian)
|
||||
{
|
||||
#if IS_LITTLE_ENDIAN
|
||||
return !littleEndian;
|
||||
#else
|
||||
return littleEndian;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
swapBytes(uint8_t x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
swapBytes(uint16_t x)
|
||||
{
|
||||
return ((x & 0xff) << 8) | (x >> 8);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
swapBytes(uint32_t x)
|
||||
{
|
||||
return ((x & 0xff) << 24) |
|
||||
((x & 0xff00) << 8) |
|
||||
((x & 0xff0000) >> 8) |
|
||||
((x & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
swapBytes(uint64_t x)
|
||||
{
|
||||
uint32_t a = x & UINT32_MAX;
|
||||
uint32_t b = x >> 32;
|
||||
return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
|
||||
}
|
||||
|
||||
template <typename DataType> struct DataToRepType { typedef DataType result; };
|
||||
template <> struct DataToRepType<int8_t> { typedef uint8_t result; };
|
||||
template <> struct DataToRepType<uint8_t> { typedef uint8_t result; };
|
||||
template <> struct DataToRepType<int16_t> { typedef uint16_t result; };
|
||||
template <> struct DataToRepType<uint16_t> { typedef uint16_t result; };
|
||||
template <> struct DataToRepType<int32_t> { typedef uint32_t result; };
|
||||
template <> struct DataToRepType<uint32_t> { typedef uint32_t result; };
|
||||
template <> struct DataToRepType<float> { typedef uint32_t result; };
|
||||
template <> struct DataToRepType<double> { typedef uint64_t result; };
|
||||
|
||||
template <typename DataType>
|
||||
struct DataViewIO
|
||||
{
|
||||
typedef typename DataToRepType<DataType>::result ReadWriteType;
|
||||
|
||||
static void fromBuffer(DataType *dest, const uint8_t *unalignedBuffer, bool wantSwap)
|
||||
{
|
||||
JS_ASSERT((reinterpret_cast<uintptr_t>(dest) & (Min<size_t>(JS_ALIGN_OF_POINTER, sizeof(DataType)) - 1)) == 0);
|
||||
memcpy((void *) dest, unalignedBuffer, sizeof(ReadWriteType));
|
||||
if (wantSwap) {
|
||||
ReadWriteType *rwDest = reinterpret_cast<ReadWriteType *>(dest);
|
||||
*rwDest = swapBytes(*rwDest);
|
||||
}
|
||||
}
|
||||
|
||||
static void toBuffer(uint8_t *unalignedBuffer, const DataType *src, bool wantSwap)
|
||||
{
|
||||
JS_ASSERT((reinterpret_cast<uintptr_t>(src) & (Min<size_t>(JS_ALIGN_OF_POINTER, sizeof(DataType)) - 1)) == 0);
|
||||
ReadWriteType temp = *reinterpret_cast<const ReadWriteType *>(src);
|
||||
if (wantSwap)
|
||||
temp = swapBytes(temp);
|
||||
memcpy(unalignedBuffer, (void *) &temp, sizeof(ReadWriteType));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename NativeType>
|
||||
bool
|
||||
DataViewObject::read(JSContext *cx, CallArgs &args, NativeType *val, const char *method)
|
||||
{
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_MORE_ARGS_NEEDED, method, "0", "s");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
if (!getDataPointer(cx, args, sizeof(NativeType), &data))
|
||||
return false;
|
||||
|
||||
bool fromLittleEndian = args.length() >= 2 && js_ValueToBoolean(args[1]);
|
||||
DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(fromLittleEndian));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename NativeType>
|
||||
static inline bool
|
||||
WebIDLCast(JSContext *cx, const Value &value, NativeType *out)
|
||||
{
|
||||
int32_t temp;
|
||||
if (!ToInt32(cx, value, &temp))
|
||||
return false;
|
||||
// Technically, the behavior of assigning an out of range value to a signed
|
||||
// variable is undefined. In practice, compilers seem to do what we want
|
||||
// without issuing any warnings.
|
||||
*out = static_cast<NativeType>(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
WebIDLCast<float>(JSContext *cx, const Value &value, float *out)
|
||||
{
|
||||
double temp;
|
||||
if (!ToNumber(cx, value, &temp))
|
||||
return false;
|
||||
*out = static_cast<float>(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
WebIDLCast<double>(JSContext *cx, const Value &value, double *out)
|
||||
{
|
||||
return ToNumber(cx, value, out);
|
||||
}
|
||||
|
||||
template<typename NativeType>
|
||||
bool
|
||||
DataViewObject::write(JSContext *cx, CallArgs &args, const char *method)
|
||||
{
|
||||
if (args.length() < 2) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_MORE_ARGS_NEEDED, method, "1", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
if (!getDataPointer(cx, args, sizeof(NativeType), &data))
|
||||
return false;
|
||||
|
||||
NativeType value;
|
||||
if (!WebIDLCast(cx, args[1], &value))
|
||||
return false;
|
||||
|
||||
bool toLittleEndian = args.length() >= 3 && js_ValueToBoolean(args[2]);
|
||||
DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(toLittleEndian));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
NonGenericProtoSearchingMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
|
||||
{
|
||||
const Value &thisv = args.thisv();
|
||||
if (thisv.isObject()) {
|
||||
JSObject *obj = thisv.toObjectOrNull();
|
||||
while (obj) {
|
||||
if (obj->getClass() == clasp) {
|
||||
*ok = true; /* quell gcc overwarning */
|
||||
return obj;
|
||||
}
|
||||
obj = obj->getProto();
|
||||
}
|
||||
}
|
||||
|
||||
*ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
int8_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt8"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
uint8_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint8"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
int16_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt16"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
uint16_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint16"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
int32_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getInt32"))
|
||||
return false;
|
||||
args.rval().setInt32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
uint32_t val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getUint32"))
|
||||
return false;
|
||||
args.rval().setNumber(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
float val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getFloat32"))
|
||||
return false;
|
||||
|
||||
args.rval().setDouble(JS_CANONICALIZE_NAN(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
double val;
|
||||
if (!obj->asDataView().read(cx, args, &val, "getFloat64"))
|
||||
return false;
|
||||
|
||||
args.rval().setDouble(JS_CANONICALIZE_NAN(val));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setInt8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setInt8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<int8_t>(cx, args, "setInt8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setUint8(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setUint8, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<uint8_t>(cx, args, "setUint8"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setInt16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setInt16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<int16_t>(cx, args, "setInt16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setUint16(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setUint16, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<uint16_t>(cx, args, "setUint16"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setInt32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setInt32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<int32_t>(cx, args, "setInt32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setUint32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setUint32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<uint32_t>(cx, args, "setUint32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setFloat32(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<float>(cx, args, "setFloat32"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
DataViewObject::fun_setFloat64(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
bool ok;
|
||||
JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &ok);
|
||||
if (!obj)
|
||||
return ok;
|
||||
|
||||
if (!obj->asDataView().write<double>(cx, args, "setFloat64"))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/***
|
||||
@ -2511,6 +3070,93 @@ InitArrayBufferClass(JSContext *cx, Handle<GlobalObject*> global)
|
||||
return arrayBufferProto;
|
||||
}
|
||||
|
||||
Class js::DataViewClass = {
|
||||
"DataView",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* hasInstance */
|
||||
NULL, /* trace */
|
||||
JS_NULL_CLASS_EXT,
|
||||
JS_NULL_OBJECT_OPS
|
||||
};
|
||||
|
||||
JSPropertySpec DataViewObject::jsprops[] = {
|
||||
{ "byteLength",
|
||||
-1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
DataViewObject::prop_getByteLength, JS_StrictPropertyStub },
|
||||
{ "byteOffset",
|
||||
-1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
DataViewObject::prop_getByteOffset, JS_StrictPropertyStub },
|
||||
{ "buffer",
|
||||
-1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
DataViewObject::prop_getBuffer, JS_StrictPropertyStub },
|
||||
{0,0,0,0,0}
|
||||
};
|
||||
|
||||
JSFunctionSpec DataViewObject::jsfuncs[] = {
|
||||
JS_FN("getInt8", DataViewObject::fun_getInt8, 1,0),
|
||||
JS_FN("getUint8", DataViewObject::fun_getUint8, 1,0),
|
||||
JS_FN("getInt16", DataViewObject::fun_getInt16, 2,0),
|
||||
JS_FN("getUint16", DataViewObject::fun_getUint16, 2,0),
|
||||
JS_FN("getInt32", DataViewObject::fun_getInt32, 2,0),
|
||||
JS_FN("getUint32", DataViewObject::fun_getUint32, 2,0),
|
||||
JS_FN("getFloat32", DataViewObject::fun_getFloat32, 2,0),
|
||||
JS_FN("getFloat64", DataViewObject::fun_getFloat64, 2,0),
|
||||
JS_FN("setInt8", DataViewObject::fun_setInt8, 2,0),
|
||||
JS_FN("setUint8", DataViewObject::fun_setUint8, 2,0),
|
||||
JS_FN("setInt16", DataViewObject::fun_setInt16, 3,0),
|
||||
JS_FN("setUint16", DataViewObject::fun_setUint16, 3,0),
|
||||
JS_FN("setInt32", DataViewObject::fun_setInt32, 3,0),
|
||||
JS_FN("setUint32", DataViewObject::fun_setUint32, 3,0),
|
||||
JS_FN("setFloat32", DataViewObject::fun_setFloat32, 3,0),
|
||||
JS_FN("setFloat64", DataViewObject::fun_setFloat64, 3,0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
JSObject *
|
||||
DataViewObject::initClass(JSContext *cx, GlobalObject *global)
|
||||
{
|
||||
JSObject *proto = global->createBlankPrototype(cx, &DataViewClass);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
DataViewObject &dvobj = proto->asDataView();
|
||||
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(0));
|
||||
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(0));
|
||||
dvobj.setFixedSlot(BUFFER_SLOT, JSVAL_VOID);
|
||||
dvobj.setPrivate(NULL);
|
||||
|
||||
JSFunction *ctor =
|
||||
global->createConstructor(cx, DataViewObject::class_constructor,
|
||||
CLASS_ATOM(cx, DataView), 3);
|
||||
if (!ctor)
|
||||
return NULL;
|
||||
|
||||
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
if (!DefinePropertiesAndBrand(cx, proto, DataViewObject::jsprops, DataViewObject::jsfuncs))
|
||||
return NULL;
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, JSProto_DataView, ctor, proto))
|
||||
return NULL;
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@ -2533,7 +3179,8 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
|
||||
!InitTypedArrayClass<Uint32Array>(cx, global) ||
|
||||
!InitTypedArrayClass<Float32Array>(cx, global) ||
|
||||
!InitTypedArrayClass<Float64Array>(cx, global) ||
|
||||
!InitTypedArrayClass<Uint8ClampedArray>(cx, global))
|
||||
!InitTypedArrayClass<Uint8ClampedArray>(cx, global) ||
|
||||
!DataViewObject::initClass(cx, global))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -2561,7 +3208,7 @@ JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
return obj->isTypedArray();
|
||||
return obj->isTypedArray() || obj->isDataView();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
@ -2698,18 +3345,49 @@ JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx)
|
||||
return static_cast<double *>(TypedArray::getDataOffset(obj));
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
*isDataView = obj->isDataView();
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
return obj->asDataView().byteOffset();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetDataViewData(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isDataView());
|
||||
return obj->asDataView().dataPointer();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetDataViewByteLength(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isDataView());
|
||||
return obj->asDataView().byteLength();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return TypedArray::getDataOffset(obj);
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return obj->isDataView() ? obj->asDataView().dataPointer() : TypedArray::getDataOffset(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx)
|
||||
{
|
||||
obj = UnwrapObject(obj);
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getSlot(TypedArray::FIELD_BYTELENGTH).toInt32();
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return obj->isDataView() ? obj->asDataView().byteLength() : TypedArray::getByteLength(obj);
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsclass.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
|
||||
@ -313,6 +314,59 @@ IsTypedArrayProto(JSObject *obj)
|
||||
return IsTypedArrayProtoClass(obj->getClass());
|
||||
}
|
||||
|
||||
class DataViewObject : public JSObject
|
||||
{
|
||||
static const size_t BYTEOFFSET_SLOT = 0;
|
||||
static const size_t BYTELENGTH_SLOT = 1;
|
||||
static const size_t BUFFER_SLOT = 2;
|
||||
|
||||
public:
|
||||
static const size_t RESERVED_SLOTS = 3;
|
||||
|
||||
static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
|
||||
static JSBool class_constructor(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static inline DataViewObject *
|
||||
create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength, Handle<ArrayBufferObject*> arrayBuffer);
|
||||
|
||||
static JSBool fun_getInt8(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getUint8(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getInt16(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getUint16(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getInt32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getUint32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getFloat32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_getFloat64(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setInt8(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setUint8(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setInt16(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setUint16(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setInt32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setUint32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);
|
||||
static JSBool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
|
||||
inline uint32_t byteLength();
|
||||
inline uint32_t byteOffset();
|
||||
inline JSObject & arrayBuffer();
|
||||
inline void *dataPointer();
|
||||
inline bool hasBuffer() const;
|
||||
static JSObject *initClass(JSContext *cx, GlobalObject *global);
|
||||
bool getDataPointer(JSContext *cx, CallArgs args, size_t typeSize, uint8_t **data);
|
||||
template<typename NativeType>
|
||||
bool read(JSContext *cx, CallArgs &args, NativeType *val, const char *method);
|
||||
template<typename NativeType>
|
||||
bool write(JSContext *cx, CallArgs &args, const char *method);
|
||||
private:
|
||||
static JSPropertySpec jsprops[];
|
||||
static JSFunctionSpec jsfuncs[];
|
||||
};
|
||||
|
||||
bool
|
||||
IsDataView(JSObject *obj);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* jstypedarray_h */
|
||||
|
@ -42,6 +42,9 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsobj.h"
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
inline uint32_t
|
||||
js::ArrayBufferObject::byteLength() const
|
||||
@ -63,6 +66,13 @@ JSObject::asArrayBuffer()
|
||||
return *static_cast<js::ArrayBufferObject *>(this);
|
||||
}
|
||||
|
||||
inline js::DataViewObject &
|
||||
JSObject::asDataView()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return *static_cast<js::DataViewObject *>(this);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
@ -117,6 +127,69 @@ TypedArray::getDataOffset(JSObject *obj) {
|
||||
return (void *)obj->getPrivate(NUM_FIXED_SLOTS);
|
||||
}
|
||||
|
||||
inline DataViewObject *
|
||||
DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Handle<ArrayBufferObject*> arrayBuffer)
|
||||
{
|
||||
JS_ASSERT(byteOffset <= INT32_MAX);
|
||||
JS_ASSERT(byteLength <= INT32_MAX);
|
||||
|
||||
RootedVarObject obj(cx, NewBuiltinClassInstance(cx, &DataViewClass));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(arrayBuffer->isArrayBuffer());
|
||||
|
||||
DataViewObject &dvobj = obj->asDataView();
|
||||
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
|
||||
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||
dvobj.setPrivate(arrayBuffer->dataPointer() + byteOffset);
|
||||
|
||||
JS_ASSERT(dvobj.numFixedSlots() == RESERVED_SLOTS);
|
||||
|
||||
return &dvobj;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
DataViewObject::byteLength()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
int32_t length = getReservedSlot(BYTELENGTH_SLOT).toInt32();
|
||||
JS_ASSERT(length >= 0);
|
||||
return static_cast<uint32_t>(length);
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
DataViewObject::byteOffset()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
int32_t offset = getReservedSlot(BYTEOFFSET_SLOT).toInt32();
|
||||
JS_ASSERT(offset >= 0);
|
||||
return static_cast<uint32_t>(offset);
|
||||
}
|
||||
|
||||
inline void *
|
||||
DataViewObject::dataPointer()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return getPrivate();
|
||||
}
|
||||
|
||||
inline JSObject &
|
||||
DataViewObject::arrayBuffer()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return getReservedSlot(BUFFER_SLOT).toObject();
|
||||
}
|
||||
|
||||
inline bool
|
||||
DataViewObject::hasBuffer() const
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return getReservedSlot(BUFFER_SLOT).isObject();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jstypedarrayinlines_h */
|
||||
|
1600
js/src/tests/js1_8_5/extensions/dataview.js
Normal file
1600
js/src/tests/js1_8_5/extensions/dataview.js
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user