summaryrefslogtreecommitdiffstats
path: root/js/src/vm/TypedArrayObject.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/vm/TypedArrayObject.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/vm/TypedArrayObject.h')
-rw-r--r--js/src/vm/TypedArrayObject.h607
1 files changed, 607 insertions, 0 deletions
diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h
new file mode 100644
index 000000000..775a9a0af
--- /dev/null
+++ b/js/src/vm/TypedArrayObject.h
@@ -0,0 +1,607 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_TypedArrayObject_h
+#define vm_TypedArrayObject_h
+
+#include "mozilla/Attributes.h"
+
+#include "jsobj.h"
+
+#include "gc/Barrier.h"
+#include "js/Class.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/SharedArrayObject.h"
+
+#define JS_FOR_EACH_TYPED_ARRAY(macro) \
+ macro(int8_t, Int8) \
+ macro(uint8_t, Uint8) \
+ macro(int16_t, Int16) \
+ macro(uint16_t, Uint16) \
+ macro(int32_t, Int32) \
+ macro(uint32_t, Uint32) \
+ macro(float, Float32) \
+ macro(double, Float64) \
+ macro(uint8_clamped, Uint8Clamped)
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+enum class TypedArrayLength { Fixed, Dynamic };
+
+/*
+ * TypedArrayObject
+ *
+ * The non-templated base class for the specific typed implementations.
+ * This class holds all the member variables that are used by
+ * the subclasses.
+ */
+
+class TypedArrayObject : public NativeObject
+{
+ public:
+ // Underlying (Shared)ArrayBufferObject.
+ static const size_t BUFFER_SLOT = 0;
+ static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right buffer slot");
+
+ // Slot containing length of the view in number of typed elements.
+ static const size_t LENGTH_SLOT = 1;
+ static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right length slot");
+
+ // Offset of view within underlying (Shared)ArrayBufferObject.
+ static const size_t BYTEOFFSET_SLOT = 2;
+ static_assert(BYTEOFFSET_SLOT == JS_TYPEDARRAYLAYOUT_BYTEOFFSET_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right byteOffset slot");
+
+ static const size_t RESERVED_SLOTS = 3;
+
+#ifdef DEBUG
+ static const uint8_t ZeroLengthArrayData = 0x4A;
+#endif
+
+ static int lengthOffset();
+ static int dataOffset();
+
+ // The raw pointer to the buffer memory, the "private" value.
+ //
+ // This offset is exposed for performance reasons - so that it
+ // need not be looked up on accesses.
+ static const size_t DATA_SLOT = 3;
+
+ static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
+ "bad inlined constant in jsfriendapi.h");
+
+ typedef TypedArrayObject SomeTypedArray;
+ typedef ArrayBufferObject BufferType;
+
+ template<typename T> struct OfType;
+
+ static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
+ // Inline buffers.
+ if (!a->hasBuffer() || !b->hasBuffer())
+ return a.get() == b.get();
+
+ // Shared buffers.
+ if (a->isSharedMemory() && b->isSharedMemory()) {
+ return (a->bufferObject()->as<SharedArrayBufferObject>().globalID() ==
+ b->bufferObject()->as<SharedArrayBufferObject>().globalID());
+ }
+
+ return a->bufferObject() == b->bufferObject();
+ }
+
+ static const Class classes[Scalar::MaxTypedArrayViewType];
+ static const Class protoClasses[Scalar::MaxTypedArrayViewType];
+ static const Class sharedTypedArrayPrototypeClass;
+
+ static const Class* classForType(Scalar::Type type) {
+ MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
+ return &classes[type];
+ }
+
+ static const Class* protoClassForType(Scalar::Type type) {
+ MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
+ return &protoClasses[type];
+ }
+
+ 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 =
+ (NativeObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
+
+ static gc::AllocKind
+ AllocKindForLazyBuffer(size_t nbytes)
+ {
+ MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
+ if (nbytes == 0)
+ nbytes += sizeof(uint8_t);
+ size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
+ MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
+ return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
+ }
+
+ inline Scalar::Type type() const;
+ inline size_t bytesPerElement() const;
+
+ static Value bufferValue(TypedArrayObject* tarr) {
+ return tarr->getFixedSlot(BUFFER_SLOT);
+ }
+ static Value byteOffsetValue(TypedArrayObject* tarr) {
+ Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+ static Value byteLengthValue(TypedArrayObject* tarr) {
+ return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
+ }
+ static Value lengthValue(TypedArrayObject* tarr) {
+ return tarr->getFixedSlot(LENGTH_SLOT);
+ }
+
+ static bool
+ ensureHasBuffer(JSContext* cx, Handle<TypedArrayObject*> tarray);
+
+ bool hasBuffer() const {
+ return bufferValue(const_cast<TypedArrayObject*>(this)).isObject();
+ }
+ JSObject* bufferObject() const {
+ return bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ }
+ uint32_t byteOffset() const {
+ return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+ uint32_t byteLength() const {
+ return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+ uint32_t length() const {
+ return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+
+ bool hasInlineElements() const;
+ void setInlineElements();
+ uint8_t* elementsRaw() const {
+ return *(uint8_t **)((((char *)this) + this->dataOffset()));
+ }
+ uint8_t* elements() const {
+ assertZeroLengthArrayData();
+ return elementsRaw();
+ }
+
+#ifdef DEBUG
+ void assertZeroLengthArrayData() const;
+#else
+ void assertZeroLengthArrayData() const {};
+#endif
+
+ Value getElement(uint32_t index);
+ static void setElement(TypedArrayObject& obj, uint32_t index, double d);
+
+ void notifyBufferDetached(JSContext* cx, void* newData);
+
+ static bool
+ GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
+ MutableHandleObject res);
+
+ /*
+ * Byte length above which created typed arrays and data views will have
+ * singleton types regardless of the context in which they are created.
+ */
+ static const uint32_t SINGLETON_BYTE_LENGTH = 1024 * 1024 * 10;
+
+ static bool isOriginalLengthGetter(Native native);
+
+ ArrayBufferObject* bufferUnshared() const {
+ MOZ_ASSERT(!isSharedMemory());
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ return &obj->as<ArrayBufferObject>();
+ }
+ SharedArrayBufferObject* bufferShared() const {
+ MOZ_ASSERT(isSharedMemory());
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ return &obj->as<SharedArrayBufferObject>();
+ }
+ ArrayBufferObjectMaybeShared* bufferEither() const {
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ if (isSharedMemory())
+ return &obj->as<SharedArrayBufferObject>();
+ return &obj->as<ArrayBufferObject>();
+ }
+
+ SharedMem<void*> viewDataShared() const {
+ return SharedMem<void*>::shared(viewDataEither_());
+ }
+ SharedMem<void*> viewDataEither() const {
+ if (isSharedMemory())
+ return SharedMem<void*>::shared(viewDataEither_());
+ return SharedMem<void*>::unshared(viewDataEither_());
+ }
+ void initViewData(SharedMem<uint8_t*> viewData) {
+ // Install a pointer to the buffer location that corresponds
+ // to offset zero within the typed array.
+ //
+ // The following unwrap is safe because the DATA_SLOT is
+ // accessed only from jitted code and from the
+ // viewDataEither_() accessor below; in neither case does the
+ // raw pointer escape untagged into C++ code.
+ initPrivate(viewData.unwrap(/*safe - see above*/));
+ }
+ void* viewDataUnshared() const {
+ MOZ_ASSERT(!isSharedMemory());
+ return viewDataEither_();
+ }
+
+ bool hasDetachedBuffer() const {
+ // Shared buffers can't be detached.
+ if (isSharedMemory())
+ return false;
+
+ // A typed array with a null buffer has never had its buffer exposed to
+ // become detached.
+ ArrayBufferObject* buffer = bufferUnshared();
+ if (!buffer)
+ return false;
+
+ return buffer->isDetached();
+ }
+
+ private:
+ void* viewDataEither_() const {
+ // Note, do not check whether shared or not
+ // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
+ return static_cast<void*>(getPrivate(DATA_SLOT));
+ }
+
+ public:
+ static void trace(JSTracer* trc, JSObject* obj);
+ static void finalize(FreeOp* fop, JSObject* obj);
+ static void objectMoved(JSObject* obj, const JSObject* old);
+ static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
+ gc::AllocKind allocKind);
+
+ /* Initialization bits */
+
+ template<Value ValueGetter(TypedArrayObject* tarr)>
+ static bool
+ GetterImpl(JSContext* cx, const CallArgs& args)
+ {
+ MOZ_ASSERT(is(args.thisv()));
+ args.rval().set(ValueGetter(&args.thisv().toObject().as<TypedArrayObject>()));
+ return true;
+ }
+
+ // ValueGetter is a function that takes an unwrapped typed array object and
+ // returns a Value. Given such a function, Getter<> is a native that
+ // retrieves a given Value, probably from a slot on the object.
+ template<Value ValueGetter(TypedArrayObject* tarr)>
+ static bool
+ Getter(JSContext* cx, unsigned argc, Value* vp)
+ {
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, GetterImpl<ValueGetter>>(cx, args);
+ }
+
+ static const JSFunctionSpec protoFunctions[];
+ static const JSPropertySpec protoAccessors[];
+ static const JSFunctionSpec staticFunctions[];
+ static const JSPropertySpec staticProperties[];
+
+ /* Accessors and functions */
+
+ static bool is(HandleValue v);
+
+ static bool set(JSContext* cx, unsigned argc, Value* vp);
+};
+
+MOZ_MUST_USE bool TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp);
+
+extern TypedArrayObject*
+TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj, int32_t len);
+
+inline bool
+IsTypedArrayClass(const Class* clasp)
+{
+ return &TypedArrayObject::classes[0] <= clasp &&
+ clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
+}
+
+bool
+IsTypedArrayConstructor(HandleValue v, uint32_t type);
+
+inline Scalar::Type
+TypedArrayObject::type() const
+{
+ MOZ_ASSERT(IsTypedArrayClass(getClass()));
+ return static_cast<Scalar::Type>(getClass() - &classes[0]);
+}
+
+inline size_t
+TypedArrayObject::bytesPerElement() const
+{
+ return Scalar::byteSize(type());
+}
+
+// Return value is whether the string is some integer. If the string is an
+// integer which is not representable as a uint64_t, the return value is true
+// and the resulting index is UINT64_MAX.
+template <typename CharT>
+bool
+StringIsTypedArrayIndex(const CharT* s, size_t length, uint64_t* indexp);
+
+inline bool
+IsTypedArrayIndex(jsid id, uint64_t* indexp)
+{
+ if (JSID_IS_INT(id)) {
+ int32_t i = JSID_TO_INT(id);
+ MOZ_ASSERT(i >= 0);
+ *indexp = (double)i;
+ return true;
+ }
+
+ if (MOZ_UNLIKELY(!JSID_IS_STRING(id)))
+ return false;
+
+ JS::AutoCheckCannotGC nogc;
+ JSAtom* atom = JSID_TO_ATOM(id);
+ size_t length = atom->length();
+
+ if (atom->hasLatin1Chars()) {
+ const Latin1Char* s = atom->latin1Chars(nogc);
+ if (!JS7_ISDEC(*s) && *s != '-')
+ return false;
+ return StringIsTypedArrayIndex(s, length, indexp);
+ }
+
+ const char16_t* s = atom->twoByteChars(nogc);
+ if (!JS7_ISDEC(*s) && *s != '-')
+ return false;
+ return StringIsTypedArrayIndex(s, length, indexp);
+}
+
+/*
+ * Implements [[DefineOwnProperty]] for TypedArrays when the property
+ * key is a TypedArray index.
+ */
+bool
+DefineTypedArrayElement(JSContext* cx, HandleObject arr, uint64_t index,
+ Handle<PropertyDescriptor> desc, ObjectOpResult& result);
+
+static inline unsigned
+TypedArrayShift(Scalar::Type viewType)
+{
+ switch (viewType) {
+ case Scalar::Int8:
+ case Scalar::Uint8:
+ case Scalar::Uint8Clamped:
+ return 0;
+ case Scalar::Int16:
+ case Scalar::Uint16:
+ return 1;
+ case Scalar::Int32:
+ case Scalar::Uint32:
+ case Scalar::Float32:
+ return 2;
+ case Scalar::Int64:
+ case Scalar::Float64:
+ return 3;
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ return 4;
+ default:;
+ }
+ MOZ_CRASH("Unexpected array type");
+}
+
+static inline unsigned
+TypedArrayElemSize(Scalar::Type viewType)
+{
+ return 1u << TypedArrayShift(viewType);
+}
+
+// Assign
+//
+// target[targetOffset] = unsafeSrcCrossCompartment[0]
+// ...
+// target[targetOffset + unsafeSrcCrossCompartment.length - 1] =
+// unsafeSrcCrossCompartment[unsafeSrcCrossCompartment.length - 1]
+//
+// where the source element range doesn't overlap the target element range in
+// memory.
+extern void
+SetDisjointTypedElements(TypedArrayObject* target, uint32_t targetOffset,
+ TypedArrayObject* unsafeSrcCrossCompartment);
+
+extern JSObject*
+InitDataViewClass(JSContext* cx, HandleObject obj);
+
+class DataViewObject : public NativeObject
+{
+ private:
+ static const Class protoClass;
+
+ static bool is(HandleValue v) {
+ return v.isObject() && v.toObject().hasClass(&class_);
+ }
+
+ template <typename NativeType>
+ static uint8_t*
+ getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, double offset);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ getterImpl(JSContext* cx, const CallArgs& args);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ getter(JSContext* cx, unsigned argc, Value* vp);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
+
+ static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
+ uint32_t *byteOffset, uint32_t* byteLength);
+ static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
+ static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
+
+ friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
+ static DataViewObject*
+ create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
+ Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto);
+
+ public:
+ static const Class class_;
+
+ static Value byteOffsetValue(DataViewObject* view) {
+ Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+
+ static Value byteLengthValue(DataViewObject* view) {
+ Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+
+ static Value bufferValue(DataViewObject* view) {
+ return view->getFixedSlot(TypedArrayObject::BUFFER_SLOT);
+ }
+
+ uint32_t byteOffset() const {
+ return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
+ }
+
+ uint32_t byteLength() const {
+ return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
+ }
+
+ ArrayBufferObject& arrayBuffer() const {
+ return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
+ }
+
+ void* dataPointer() const {
+ return getPrivate();
+ }
+
+ static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getFloat32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getFloat32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getFloat64Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getFloat64(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setFloat32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setFloat32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setFloat64Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool initClass(JSContext* cx);
+ static void notifyBufferDetached(JSObject* view);
+ template<typename NativeType>
+ static bool read(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, NativeType* val, const char* method);
+ template<typename NativeType>
+ static bool write(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, const char* method);
+
+ void notifyBufferDetached(void* newData);
+
+ private:
+ static const JSFunctionSpec jsfuncs[];
+};
+
+static inline int32_t
+ClampIntForUint8Array(int32_t x)
+{
+ if (x < 0)
+ return 0;
+ if (x > 255)
+ return 255;
+ return x;
+}
+
+static inline bool
+IsAnyArrayBuffer(HandleObject obj)
+{
+ return IsArrayBuffer(obj) || IsSharedArrayBuffer(obj);
+}
+
+static inline bool
+IsAnyArrayBuffer(JSObject* obj)
+{
+ return IsArrayBuffer(obj) || IsSharedArrayBuffer(obj);
+}
+
+static inline bool
+IsAnyArrayBuffer(HandleValue v)
+{
+ return v.isObject() && IsAnyArrayBuffer(&v.toObject());
+}
+
+} // namespace js
+
+template <>
+inline bool
+JSObject::is<js::TypedArrayObject>() const
+{
+ return js::IsTypedArrayClass(getClass());
+}
+
+#endif /* vm_TypedArrayObject_h */