diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/vm/UnboxedObject-inl.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-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/UnboxedObject-inl.h')
-rw-r--r-- | js/src/vm/UnboxedObject-inl.h | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h new file mode 100644 index 000000000..93ad7bf28 --- /dev/null +++ b/js/src/vm/UnboxedObject-inl.h @@ -0,0 +1,840 @@ +/* -*- 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_UnboxedObject_inl_h +#define vm_UnboxedObject_inl_h + +#include "vm/UnboxedObject.h" + +#include "gc/StoreBuffer-inl.h" +#include "vm/ArrayObject-inl.h" +#include "vm/NativeObject-inl.h" + +namespace js { + +static inline Value +GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized) +{ + switch (type) { + case JSVAL_TYPE_BOOLEAN: + return BooleanValue(*p != 0); + + case JSVAL_TYPE_INT32: + return Int32Value(*reinterpret_cast<int32_t*>(p)); + + case JSVAL_TYPE_DOUBLE: { + // During unboxed plain object creation, non-GC thing properties are + // left uninitialized. This is normally fine, since the properties will + // be filled in shortly, but if they are read before that happens we + // need to make sure that doubles are canonical. + double d = *reinterpret_cast<double*>(p); + if (maybeUninitialized) + return DoubleValue(JS::CanonicalizeNaN(d)); + return DoubleValue(d); + } + + case JSVAL_TYPE_STRING: + return StringValue(*reinterpret_cast<JSString**>(p)); + + case JSVAL_TYPE_OBJECT: + return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p)); + + default: + MOZ_CRASH("Invalid type for unboxed value"); + } +} + +static inline void +SetUnboxedValueNoTypeChange(JSObject* unboxedObject, + uint8_t* p, JSValueType type, const Value& v, + bool preBarrier) +{ + switch (type) { + case JSVAL_TYPE_BOOLEAN: + *p = v.toBoolean(); + return; + + case JSVAL_TYPE_INT32: + *reinterpret_cast<int32_t*>(p) = v.toInt32(); + return; + + case JSVAL_TYPE_DOUBLE: + *reinterpret_cast<double*>(p) = v.toNumber(); + return; + + case JSVAL_TYPE_STRING: { + MOZ_ASSERT(!IsInsideNursery(v.toString())); + JSString** np = reinterpret_cast<JSString**>(p); + if (preBarrier) + JSString::writeBarrierPre(*np); + *np = v.toString(); + return; + } + + case JSVAL_TYPE_OBJECT: { + JSObject** np = reinterpret_cast<JSObject**>(p); + + // Manually trigger post barriers on the whole object. If we treat + // the pointer as a HeapPtrObject we will get confused later if the + // object is converted to its native representation. + JSObject* obj = v.toObjectOrNull(); + if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) { + JSRuntime* rt = unboxedObject->runtimeFromMainThread(); + rt->gc.storeBuffer.putWholeCell(unboxedObject); + } + + if (preBarrier) + JSObject::writeBarrierPre(*np); + *np = obj; + return; + } + + default: + MOZ_CRASH("Invalid type for unboxed value"); + } +} + +static inline bool +SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id, + uint8_t* p, JSValueType type, const Value& v, bool preBarrier) +{ + switch (type) { + case JSVAL_TYPE_BOOLEAN: + if (v.isBoolean()) { + *p = v.toBoolean(); + return true; + } + return false; + + case JSVAL_TYPE_INT32: + if (v.isInt32()) { + *reinterpret_cast<int32_t*>(p) = v.toInt32(); + return true; + } + return false; + + case JSVAL_TYPE_DOUBLE: + if (v.isNumber()) { + *reinterpret_cast<double*>(p) = v.toNumber(); + return true; + } + return false; + + case JSVAL_TYPE_STRING: + if (v.isString()) { + MOZ_ASSERT(!IsInsideNursery(v.toString())); + JSString** np = reinterpret_cast<JSString**>(p); + if (preBarrier) + JSString::writeBarrierPre(*np); + *np = v.toString(); + return true; + } + return false; + + case JSVAL_TYPE_OBJECT: + if (v.isObjectOrNull()) { + JSObject** np = reinterpret_cast<JSObject**>(p); + + // Update property types when writing object properties. Types for + // other properties were captured when the unboxed layout was + // created. + AddTypePropertyId(cx, unboxedObject, id, v); + + // As above, trigger post barriers on the whole object. + JSObject* obj = v.toObjectOrNull(); + if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) { + JSRuntime* rt = unboxedObject->runtimeFromMainThread(); + rt->gc.storeBuffer.putWholeCell(unboxedObject); + } + + if (preBarrier) + JSObject::writeBarrierPre(*np); + *np = obj; + return true; + } + return false; + + default: + MOZ_CRASH("Invalid type for unboxed value"); + } +} + +///////////////////////////////////////////////////////////////////// +// UnboxedPlainObject +///////////////////////////////////////////////////////////////////// + +inline const UnboxedLayout& +UnboxedPlainObject::layout() const +{ + return group()->unboxedLayout(); +} + +///////////////////////////////////////////////////////////////////// +// UnboxedArrayObject +///////////////////////////////////////////////////////////////////// + +inline const UnboxedLayout& +UnboxedArrayObject::layout() const +{ + return group()->unboxedLayout(); +} + +inline void +UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length) +{ + if (length > INT32_MAX) { + // Track objects with overflowing lengths in type information. + MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW); + } + + length_ = length; +} + +inline void +UnboxedArrayObject::setInitializedLength(uint32_t initlen) +{ + if (initlen < initializedLength()) { + switch (elementType()) { + case JSVAL_TYPE_STRING: + for (size_t i = initlen; i < initializedLength(); i++) + triggerPreBarrier<JSVAL_TYPE_STRING>(i); + break; + case JSVAL_TYPE_OBJECT: + for (size_t i = initlen; i < initializedLength(); i++) + triggerPreBarrier<JSVAL_TYPE_OBJECT>(i); + break; + default: + MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType())); + } + } + setInitializedLengthNoBarrier(initlen); +} + +template <JSValueType Type> +inline bool +UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) +{ + MOZ_ASSERT(index < initializedLength()); + MOZ_ASSERT(Type == elementType()); + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true); +} + +template <JSValueType Type> +inline void +UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v) +{ + MOZ_ASSERT(index < initializedLength()); + MOZ_ASSERT(Type == elementType()); + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true); +} + +template <JSValueType Type> +inline bool +UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v) +{ + MOZ_ASSERT(index < initializedLength()); + MOZ_ASSERT(Type == elementType()); + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false); +} + +template <JSValueType Type> +inline void +UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v) +{ + MOZ_ASSERT(index < initializedLength()); + MOZ_ASSERT(Type == elementType()); + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false); +} + +template <JSValueType Type> +inline Value +UnboxedArrayObject::getElementSpecific(size_t index) +{ + MOZ_ASSERT(index < initializedLength()); + MOZ_ASSERT(Type == elementType()); + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false); +} + +template <JSValueType Type> +inline void +UnboxedArrayObject::triggerPreBarrier(size_t index) +{ + MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type)); + + uint8_t* p = elements() + index * UnboxedTypeSize(Type); + + switch (Type) { + case JSVAL_TYPE_STRING: { + JSString** np = reinterpret_cast<JSString**>(p); + JSString::writeBarrierPre(*np); + break; + } + + case JSVAL_TYPE_OBJECT: { + JSObject** np = reinterpret_cast<JSObject**>(p); + JSObject::writeBarrierPre(*np); + break; + } + + default: + MOZ_CRASH("Bad type"); + } +} + +///////////////////////////////////////////////////////////////////// +// Combined methods for NativeObject and UnboxedArrayObject accesses. +///////////////////////////////////////////////////////////////////// + +static inline bool +HasAnyBoxedOrUnboxedDenseElements(JSObject* obj) +{ + return obj->isNative() || obj->is<UnboxedArrayObject>(); +} + +static inline size_t +GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj) +{ + if (obj->isNative()) + return obj->as<NativeObject>().getDenseInitializedLength(); + if (obj->is<UnboxedArrayObject>()) + return obj->as<UnboxedArrayObject>().initializedLength(); + return 0; +} + +static inline size_t +GetAnyBoxedOrUnboxedCapacity(JSObject* obj) +{ + if (obj->isNative()) + return obj->as<NativeObject>().getDenseCapacity(); + if (obj->is<UnboxedArrayObject>()) + return obj->as<UnboxedArrayObject>().capacity(); + return 0; +} + +static inline Value +GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) +{ + if (obj->isNative()) + return obj->as<NativeObject>().getDenseElement(index); + return obj->as<UnboxedArrayObject>().getElement(index); +} + +static inline size_t +GetAnyBoxedOrUnboxedArrayLength(JSObject* obj) +{ + if (obj->is<ArrayObject>()) + return obj->as<ArrayObject>().length(); + return obj->as<UnboxedArrayObject>().length(); +} + +static inline void +SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length) +{ + if (obj->is<ArrayObject>()) { + MOZ_ASSERT(length >= obj->as<ArrayObject>().length()); + obj->as<ArrayObject>().setLength(cx, length); + } else { + MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length()); + obj->as<UnboxedArrayObject>().setLength(cx, length); + } +} + +static inline bool +SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) +{ + if (obj->isNative()) { + obj->as<NativeObject>().setDenseElementWithType(cx, index, value); + return true; + } + return obj->as<UnboxedArrayObject>().setElement(cx, index, value); +} + +static inline bool +InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) +{ + if (obj->isNative()) { + obj->as<NativeObject>().initDenseElementWithType(cx, index, value); + return true; + } + return obj->as<UnboxedArrayObject>().initElement(cx, index, value); +} + +///////////////////////////////////////////////////////////////////// +// Template methods for NativeObject and UnboxedArrayObject accesses. +///////////////////////////////////////////////////////////////////// + +static inline JSValueType +GetBoxedOrUnboxedType(JSObject* obj) +{ + if (obj->isNative()) + return JSVAL_TYPE_MAGIC; + return obj->as<UnboxedArrayObject>().elementType(); +} + +template <JSValueType Type> +static inline bool +HasBoxedOrUnboxedDenseElements(JSObject* obj) +{ + if (Type == JSVAL_TYPE_MAGIC) + return obj->isNative(); + return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type; +} + +template <JSValueType Type> +static inline size_t +GetBoxedOrUnboxedInitializedLength(JSObject* obj) +{ + if (Type == JSVAL_TYPE_MAGIC) + return obj->as<NativeObject>().getDenseInitializedLength(); + return obj->as<UnboxedArrayObject>().initializedLength(); +} + +template <JSValueType Type> +static inline DenseElementResult +SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen) +{ + size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj); + if (Type == JSVAL_TYPE_MAGIC) { + obj->as<NativeObject>().setDenseInitializedLength(initlen); + if (initlen < oldInitlen) + obj->as<NativeObject>().shrinkElements(cx, initlen); + } else { + obj->as<UnboxedArrayObject>().setInitializedLength(initlen); + if (initlen < oldInitlen) + obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen); + } + return DenseElementResult::Success; +} + +template <JSValueType Type> +static inline size_t +GetBoxedOrUnboxedCapacity(JSObject* obj) +{ + if (Type == JSVAL_TYPE_MAGIC) + return obj->as<NativeObject>().getDenseCapacity(); + return obj->as<UnboxedArrayObject>().capacity(); +} + +template <JSValueType Type> +static inline Value +GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index) +{ + if (Type == JSVAL_TYPE_MAGIC) + return obj->as<NativeObject>().getDenseElement(index); + return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index); +} + +template <JSValueType Type> +static inline void +SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value) +{ + if (Type == JSVAL_TYPE_MAGIC) + obj->as<NativeObject>().setDenseElement(index, value); + else + obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value); +} + +template <JSValueType Type> +static inline bool +SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value) +{ + if (Type == JSVAL_TYPE_MAGIC) { + obj->as<NativeObject>().setDenseElementWithType(cx, index, value); + return true; + } + return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value); +} + +template <JSValueType Type> +static inline DenseElementResult +EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count) +{ + if (Type == JSVAL_TYPE_MAGIC) { + if (!obj->as<ArrayObject>().ensureElements(cx, count)) + return DenseElementResult::Failure; + } else { + if (obj->as<UnboxedArrayObject>().capacity() < count) { + if (!obj->as<UnboxedArrayObject>().growElements(cx, count)) + return DenseElementResult::Failure; + } + } + return DenseElementResult::Success; +} + +template <JSValueType Type> +static inline DenseElementResult +SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, + uint32_t start, const Value* vp, uint32_t count, + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update) +{ + if (Type == JSVAL_TYPE_MAGIC) { + NativeObject* nobj = &obj->as<NativeObject>(); + + if (nobj->denseElementsAreFrozen()) + return DenseElementResult::Incomplete; + + if (obj->is<ArrayObject>() && + !obj->as<ArrayObject>().lengthIsWritable() && + start + count >= obj->as<ArrayObject>().length()) + { + return DenseElementResult::Incomplete; + } + + DenseElementResult result = nobj->ensureDenseElements(cx, start, count); + if (result != DenseElementResult::Success) + return result; + + if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length()) + obj->as<ArrayObject>().setLengthInt32(start + count); + + if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) { + nobj->copyDenseElements(start, vp, count); + } else { + for (size_t i = 0; i < count; i++) + nobj->setDenseElementWithType(cx, start + i, vp[i]); + } + + return DenseElementResult::Success; + } + + UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>(); + + if (start > nobj->initializedLength()) + return DenseElementResult::Incomplete; + + if (start + count >= UnboxedArrayObject::MaximumCapacity) + return DenseElementResult::Incomplete; + + if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count)) + return DenseElementResult::Failure; + + size_t oldInitlen = nobj->initializedLength(); + + // Overwrite any existing elements covered by the new range. If we fail + // after this point due to some incompatible type being written to the + // object's elements, afterwards the contents will be different from when + // we started. The caller must retry the operation using a generic path, + // which will overwrite the already-modified elements as well as the ones + // that were left alone. + size_t i = 0; + if (updateTypes == ShouldUpdateTypes::DontUpdate) { + for (size_t j = start; i < count && j < oldInitlen; i++, j++) + nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]); + } else { + for (size_t j = start; i < count && j < oldInitlen; i++, j++) { + if (!nobj->setElementSpecific<Type>(cx, j, vp[i])) + return DenseElementResult::Incomplete; + } + } + + if (i != count) { + obj->as<UnboxedArrayObject>().setInitializedLength(start + count); + if (updateTypes == ShouldUpdateTypes::DontUpdate) { + for (; i < count; i++) + nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]); + } else { + for (; i < count; i++) { + if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) { + nobj->setInitializedLengthNoBarrier(oldInitlen); + return DenseElementResult::Incomplete; + } + } + } + } + + if (start + count >= nobj->length()) + nobj->setLength(cx, start + count); + + return DenseElementResult::Success; +} + +template <JSValueType Type> +static inline DenseElementResult +MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart, + uint32_t length) +{ + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj)); + + if (Type == JSVAL_TYPE_MAGIC) { + if (obj->as<NativeObject>().denseElementsAreFrozen()) + return DenseElementResult::Incomplete; + + if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx)) + return DenseElementResult::Failure; + obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length); + } else { + uint8_t* data = obj->as<UnboxedArrayObject>().elements(); + size_t elementSize = UnboxedTypeSize(Type); + + if (UnboxedTypeNeedsPreBarrier(Type) && + JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier()) + { + // Trigger pre barriers on any elements we are overwriting. See + // NativeObject::moveDenseElements. No post barrier is needed as + // only whole cell post barriers are used with unboxed objects. + for (size_t i = 0; i < length; i++) + obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i); + } + + memmove(data + dstStart * elementSize, + data + srcStart * elementSize, + length * elementSize); + } + + return DenseElementResult::Success; +} + +template <JSValueType DstType, JSValueType SrcType> +static inline DenseElementResult +CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, + uint32_t dstStart, uint32_t srcStart, uint32_t length) +{ + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src)); + MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst)); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart); + MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length); + MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length); + + SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length); + + if (DstType == JSVAL_TYPE_MAGIC) { + if (SrcType == JSVAL_TYPE_MAGIC) { + const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart; + dst->as<NativeObject>().initDenseElements(dstStart, vp, length); + } else { + for (size_t i = 0; i < length; i++) { + Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i); + dst->as<NativeObject>().initDenseElement(dstStart + i, v); + } + } + } else if (DstType == SrcType) { + uint8_t* dstData = dst->as<UnboxedArrayObject>().elements(); + uint8_t* srcData = src->as<UnboxedArrayObject>().elements(); + size_t elementSize = UnboxedTypeSize(DstType); + + memcpy(dstData + dstStart * elementSize, + srcData + srcStart * elementSize, + length * elementSize); + + // Add a store buffer entry if we might have copied a nursery pointer to dst. + if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst)) + dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst); + } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) { + uint8_t* dstData = dst->as<UnboxedArrayObject>().elements(); + uint8_t* srcData = src->as<UnboxedArrayObject>().elements(); + + for (size_t i = 0; i < length; i++) { + int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t)); + *reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v; + } + } else { + for (size_t i = 0; i < length; i++) { + Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i); + dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v); + } + } + + return DenseElementResult::Success; +} + +///////////////////////////////////////////////////////////////////// +// Dispatch to specialized methods based on the type of an object. +///////////////////////////////////////////////////////////////////// + +// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h. +// The clang-cl front end defines _MSC_VER, but still requires the explicit +// template declaration, so we must test for __clang__ here as well. +#if defined(_MSC_VER) && !defined(__clang__) +# define DEPENDENT_TEMPLATE_HINT +#else +# define DEPENDENT_TEMPLATE_HINT template +#endif + +// Function to dispatch a method specialized to whatever boxed or unboxed dense +// elements which an input object has. +template <typename F> +DenseElementResult +CallBoxedOrUnboxedSpecialization(F f, JSObject* obj) +{ + if (!HasAnyBoxedOrUnboxedDenseElements(obj)) + return DenseElementResult::Incomplete; + switch (GetBoxedOrUnboxedType(obj)) { + case JSVAL_TYPE_MAGIC: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>(); + case JSVAL_TYPE_BOOLEAN: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>(); + case JSVAL_TYPE_INT32: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>(); + case JSVAL_TYPE_DOUBLE: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>(); + case JSVAL_TYPE_STRING: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>(); + case JSVAL_TYPE_OBJECT: + return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>(); + default: + MOZ_CRASH(); + } +} + +// As above, except the specialization can reflect the unboxed type of two objects. +template <typename F> +DenseElementResult +CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2) +{ + if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2)) + return DenseElementResult::Incomplete; + +#define SPECIALIZE_OBJ2(TYPE) \ + switch (GetBoxedOrUnboxedType(obj2)) { \ + case JSVAL_TYPE_MAGIC: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \ + case JSVAL_TYPE_BOOLEAN: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \ + case JSVAL_TYPE_INT32: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \ + case JSVAL_TYPE_DOUBLE: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \ + case JSVAL_TYPE_STRING: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \ + case JSVAL_TYPE_OBJECT: \ + return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \ + default: \ + MOZ_CRASH(); \ + } + + switch (GetBoxedOrUnboxedType(obj1)) { + case JSVAL_TYPE_MAGIC: + SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC) + case JSVAL_TYPE_BOOLEAN: + SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN) + case JSVAL_TYPE_INT32: + SPECIALIZE_OBJ2(JSVAL_TYPE_INT32) + case JSVAL_TYPE_DOUBLE: + SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE) + case JSVAL_TYPE_STRING: + SPECIALIZE_OBJ2(JSVAL_TYPE_STRING) + case JSVAL_TYPE_OBJECT: + SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT) + default: + MOZ_CRASH(); + } + +#undef SPECIALIZE_OBJ2 +} + +#undef DEPENDENT_TEMPLATE_HINT + +#define DefineBoxedOrUnboxedFunctor1(Signature, A) \ +struct Signature ## Functor { \ + A a; \ + explicit Signature ## Functor(A a) \ + : a(a) \ + {} \ + template <JSValueType Type> \ + DenseElementResult operator()() { \ + return Signature<Type>(a); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C) \ +struct Signature ## Functor { \ + A a; B b; C c; \ + Signature ## Functor(A a, B b, C c) \ + : a(a), b(b), c(c) \ + {} \ + template <JSValueType Type> \ + DenseElementResult operator()() { \ + return Signature<Type>(a, b, c); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; \ + Signature ## Functor(A a, B b, C c, D d) \ + : a(a), b(b), c(c), d(d) \ + {} \ + template <JSValueType Type> \ + DenseElementResult operator()() { \ + return Signature<Type>(a, b, c, d); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; \ + Signature ## Functor(A a, B b, C c, D d) \ + : a(a), b(b), c(c), d(d) \ + {} \ + template <JSValueType TypeOne, JSValueType TypeTwo> \ + DenseElementResult operator()() { \ + return Signature<TypeOne, TypeTwo>(a, b, c, d); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; E e; \ + Signature ## Functor(A a, B b, C c, D d, E e) \ + : a(a), b(b), c(c), d(d), e(e) \ + {} \ + template <JSValueType Type> \ + DenseElementResult operator()() { \ + return Signature<Type>(a, b, c, d, e); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; E e; F f; \ + Signature ## Functor(A a, B b, C c, D d, E e, F f) \ + : a(a), b(b), c(c), d(d), e(e), f(f) \ + {} \ + template <JSValueType Type> \ + DenseElementResult operator()() { \ + return Signature<Type>(a, b, c, d, e, f); \ + } \ +} + +#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \ +struct Signature ## Functor { \ + A a; B b; C c; D d; E e; F f; \ + Signature ## Functor(A a, B b, C c, D d, E e, F f) \ + : a(a), b(b), c(c), d(d), e(e), f(f) \ + {} \ + template <JSValueType TypeOne, JSValueType TypeTwo> \ + DenseElementResult operator()() { \ + return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f); \ + } \ +} + +DenseElementResult +SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj, + uint32_t start, const Value* vp, uint32_t count, + ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); + +DenseElementResult +MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, + uint32_t dstStart, uint32_t srcStart, uint32_t length); + +DenseElementResult +CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src, + uint32_t dstStart, uint32_t srcStart, uint32_t length); + +void +SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen); + +DenseElementResult +EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count); + +} // namespace js + +#endif // vm_UnboxedObject_inl_h |