LCOV - code coverage report
Current view: top level - js/src/vm - TypedArrayObject-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 255 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 281 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef vm_TypedArrayObject_inl_h
       8             : #define vm_TypedArrayObject_inl_h
       9             : 
      10             : /* Utilities and common inline code for TypedArray */
      11             : 
      12             : #include "vm/TypedArrayObject.h"
      13             : 
      14             : #include "mozilla/Assertions.h"
      15             : #include "mozilla/FloatingPoint.h"
      16             : #include "mozilla/PodOperations.h"
      17             : 
      18             : #include "jsarray.h"
      19             : #include "jscntxt.h"
      20             : #include "jsnum.h"
      21             : 
      22             : #include "jit/AtomicOperations.h"
      23             : 
      24             : #include "js/Conversions.h"
      25             : #include "js/Value.h"
      26             : 
      27             : #include "vm/NativeObject.h"
      28             : 
      29             : namespace js {
      30             : 
      31             : template<typename To, typename From>
      32             : inline To
      33             : ConvertNumber(From src);
      34             : 
      35             : template<>
      36             : inline int8_t
      37           0 : ConvertNumber<int8_t, float>(float src)
      38             : {
      39           0 :     return JS::ToInt8(src);
      40             : }
      41             : 
      42             : template<>
      43             : inline uint8_t
      44           0 : ConvertNumber<uint8_t, float>(float src)
      45             : {
      46           0 :     return JS::ToUint8(src);
      47             : }
      48             : 
      49             : template<>
      50             : inline uint8_clamped
      51           0 : ConvertNumber<uint8_clamped, float>(float src)
      52             : {
      53           0 :     return uint8_clamped(src);
      54             : }
      55             : 
      56             : template<>
      57             : inline int16_t
      58           0 : ConvertNumber<int16_t, float>(float src)
      59             : {
      60           0 :     return JS::ToInt16(src);
      61             : }
      62             : 
      63             : template<>
      64             : inline uint16_t
      65           0 : ConvertNumber<uint16_t, float>(float src)
      66             : {
      67           0 :     return JS::ToUint16(src);
      68             : }
      69             : 
      70             : template<>
      71             : inline int32_t
      72           0 : ConvertNumber<int32_t, float>(float src)
      73             : {
      74           0 :     return JS::ToInt32(src);
      75             : }
      76             : 
      77             : template<>
      78             : inline uint32_t
      79           0 : ConvertNumber<uint32_t, float>(float src)
      80             : {
      81           0 :     return JS::ToUint32(src);
      82             : }
      83             : 
      84             : template<> inline int8_t
      85           0 : ConvertNumber<int8_t, double>(double src)
      86             : {
      87           0 :     return JS::ToInt8(src);
      88             : }
      89             : 
      90             : template<>
      91             : inline uint8_t
      92           0 : ConvertNumber<uint8_t, double>(double src)
      93             : {
      94           0 :     return JS::ToUint8(src);
      95             : }
      96             : 
      97             : template<>
      98             : inline uint8_clamped
      99           0 : ConvertNumber<uint8_clamped, double>(double src)
     100             : {
     101           0 :     return uint8_clamped(src);
     102             : }
     103             : 
     104             : template<>
     105             : inline int16_t
     106           0 : ConvertNumber<int16_t, double>(double src)
     107             : {
     108           0 :     return JS::ToInt16(src);
     109             : }
     110             : 
     111             : template<>
     112             : inline uint16_t
     113           0 : ConvertNumber<uint16_t, double>(double src)
     114             : {
     115           0 :     return JS::ToUint16(src);
     116             : }
     117             : 
     118             : template<>
     119             : inline int32_t
     120           0 : ConvertNumber<int32_t, double>(double src)
     121             : {
     122           0 :     return JS::ToInt32(src);
     123             : }
     124             : 
     125             : template<>
     126             : inline uint32_t
     127           0 : ConvertNumber<uint32_t, double>(double src)
     128             : {
     129           0 :     return JS::ToUint32(src);
     130             : }
     131             : 
     132             : template<typename To, typename From>
     133             : inline To
     134           0 : ConvertNumber(From src)
     135             : {
     136             :     static_assert(!mozilla::IsFloatingPoint<From>::value ||
     137             :                   (mozilla::IsFloatingPoint<From>::value && mozilla::IsFloatingPoint<To>::value),
     138             :                   "conversion from floating point to int should have been handled by "
     139             :                   "specializations above");
     140           0 :     return To(src);
     141             : }
     142             : 
     143             : template<typename NativeType> struct TypeIDOfType;
     144             : template<> struct TypeIDOfType<int8_t> { static const Scalar::Type id = Scalar::Int8; };
     145             : template<> struct TypeIDOfType<uint8_t> { static const Scalar::Type id = Scalar::Uint8; };
     146             : template<> struct TypeIDOfType<int16_t> { static const Scalar::Type id = Scalar::Int16; };
     147             : template<> struct TypeIDOfType<uint16_t> { static const Scalar::Type id = Scalar::Uint16; };
     148             : template<> struct TypeIDOfType<int32_t> { static const Scalar::Type id = Scalar::Int32; };
     149             : template<> struct TypeIDOfType<uint32_t> { static const Scalar::Type id = Scalar::Uint32; };
     150             : template<> struct TypeIDOfType<float> { static const Scalar::Type id = Scalar::Float32; };
     151             : template<> struct TypeIDOfType<double> { static const Scalar::Type id = Scalar::Float64; };
     152             : template<> struct TypeIDOfType<uint8_clamped> { static const Scalar::Type id = Scalar::Uint8Clamped; };
     153             : 
     154             : class SharedOps
     155             : {
     156             :   public:
     157             :     template<typename T>
     158           0 :     static T load(SharedMem<T*> addr) {
     159           0 :         return js::jit::AtomicOperations::loadSafeWhenRacy(addr);
     160             :     }
     161             : 
     162             :     template<typename T>
     163           0 :     static void store(SharedMem<T*> addr, T value) {
     164           0 :         js::jit::AtomicOperations::storeSafeWhenRacy(addr, value);
     165           0 :     }
     166             : 
     167             :     template<typename T>
     168           0 :     static void memcpy(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
     169           0 :         js::jit::AtomicOperations::memcpySafeWhenRacy(dest, src, size);
     170           0 :     }
     171             : 
     172             :     template<typename T>
     173             :     static void memmove(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
     174             :         js::jit::AtomicOperations::memmoveSafeWhenRacy(dest, src, size);
     175             :     }
     176             : 
     177             :     template<typename T>
     178           0 :     static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
     179           0 :         js::jit::AtomicOperations::podCopySafeWhenRacy(dest, src, nelem);
     180           0 :     }
     181             : 
     182             :     template<typename T>
     183           0 :     static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
     184           0 :         js::jit::AtomicOperations::podMoveSafeWhenRacy(dest, src, nelem);
     185           0 :     }
     186             : 
     187           0 :     static SharedMem<void*> extract(TypedArrayObject* obj) {
     188           0 :         return obj->viewDataEither();
     189             :     }
     190             : };
     191             : 
     192             : class UnsharedOps
     193             : {
     194             :   public:
     195             :     template<typename T>
     196           0 :     static T load(SharedMem<T*> addr) {
     197           0 :         return *addr.unwrapUnshared();
     198             :     }
     199             : 
     200             :     template<typename T>
     201           0 :     static void store(SharedMem<T*> addr, T value) {
     202           0 :         *addr.unwrapUnshared() = value;
     203           0 :     }
     204             : 
     205             :     template<typename T>
     206           0 :     static void memcpy(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
     207           0 :         ::memcpy(dest.unwrapUnshared(), src.unwrapUnshared(), size);
     208           0 :     }
     209             : 
     210             :     template<typename T>
     211             :     static void memmove(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
     212             :         ::memmove(dest.unwrapUnshared(), src.unwrapUnshared(), size);
     213             :     }
     214             : 
     215             :     template<typename T>
     216           0 :     static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
     217           0 :         mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
     218           0 :     }
     219             : 
     220             :     template<typename T>
     221           0 :     static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
     222           0 :         mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
     223           0 :     }
     224             : 
     225           0 :     static SharedMem<void*> extract(TypedArrayObject* obj) {
     226           0 :         return SharedMem<void*>::unshared(obj->viewDataUnshared());
     227             :     }
     228             : };
     229             : 
     230             : template<typename T, typename Ops>
     231             : class ElementSpecific
     232             : {
     233             :   public:
     234             :     /*
     235             :      * Copy |source|'s elements into |target|, starting at |target[offset]|.
     236             :      * Act as if the assignments occurred from a fresh copy of |source|, in
     237             :      * case the two memory ranges overlap.
     238             :      */
     239             :     static bool
     240           0 :     setFromTypedArray(JSContext* cx,
     241             :                       Handle<TypedArrayObject*> target, Handle<TypedArrayObject*> source,
     242             :                       uint32_t offset)
     243             :     {
     244             :         // WARNING: |source| may be an unwrapped typed array from a different
     245             :         // compartment. Proceed with caution!
     246             : 
     247           0 :         MOZ_ASSERT(TypeIDOfType<T>::id == target->type(),
     248             :                    "calling wrong setFromTypedArray specialization");
     249           0 :         MOZ_ASSERT(!target->hasDetachedBuffer(), "target isn't detached");
     250           0 :         MOZ_ASSERT(!source->hasDetachedBuffer(), "source isn't detached");
     251             : 
     252           0 :         MOZ_ASSERT(offset <= target->length());
     253           0 :         MOZ_ASSERT(source->length() <= target->length() - offset);
     254             : 
     255           0 :         if (TypedArrayObject::sameBuffer(target, source))
     256           0 :             return setFromOverlappingTypedArray(cx, target, source, offset);
     257             : 
     258           0 :         SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
     259           0 :         uint32_t count = source->length();
     260             : 
     261           0 :         if (source->type() == target->type()) {
     262           0 :             Ops::podCopy(dest, source->viewDataEither().template cast<T*>(), count);
     263           0 :             return true;
     264             :         }
     265             : 
     266             :         // Inhibit unaligned accesses on ARM (bug 1097253, a compiler bug).
     267             : #ifdef __arm__
     268             : #  define JS_VOLATILE_ARM volatile
     269             : #else
     270             : #  define JS_VOLATILE_ARM
     271             : #endif
     272             : 
     273           0 :         SharedMem<void*> data = Ops::extract(source);
     274           0 :         switch (source->type()) {
     275             :           case Scalar::Int8: {
     276           0 :             SharedMem<JS_VOLATILE_ARM int8_t*> src = data.cast<JS_VOLATILE_ARM int8_t*>();
     277           0 :             for (uint32_t i = 0; i < count; ++i)
     278           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     279           0 :             break;
     280             :           }
     281             :           case Scalar::Uint8:
     282             :           case Scalar::Uint8Clamped: {
     283           0 :             SharedMem<JS_VOLATILE_ARM uint8_t*> src = data.cast<JS_VOLATILE_ARM uint8_t*>();
     284           0 :             for (uint32_t i = 0; i < count; ++i)
     285           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     286           0 :             break;
     287             :           }
     288             :           case Scalar::Int16: {
     289           0 :             SharedMem<JS_VOLATILE_ARM int16_t*> src = data.cast<JS_VOLATILE_ARM int16_t*>();
     290           0 :             for (uint32_t i = 0; i < count; ++i)
     291           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     292           0 :             break;
     293             :           }
     294             :           case Scalar::Uint16: {
     295           0 :             SharedMem<JS_VOLATILE_ARM uint16_t*> src = data.cast<JS_VOLATILE_ARM uint16_t*>();
     296           0 :             for (uint32_t i = 0; i < count; ++i)
     297           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     298           0 :             break;
     299             :           }
     300             :           case Scalar::Int32: {
     301           0 :             SharedMem<JS_VOLATILE_ARM int32_t*> src = data.cast<JS_VOLATILE_ARM int32_t*>();
     302           0 :             for (uint32_t i = 0; i < count; ++i)
     303           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     304           0 :             break;
     305             :           }
     306             :           case Scalar::Uint32: {
     307           0 :             SharedMem<JS_VOLATILE_ARM uint32_t*> src = data.cast<JS_VOLATILE_ARM uint32_t*>();
     308           0 :             for (uint32_t i = 0; i < count; ++i)
     309           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     310           0 :             break;
     311             :           }
     312             :           case Scalar::Float32: {
     313           0 :             SharedMem<JS_VOLATILE_ARM float*> src = data.cast<JS_VOLATILE_ARM float*>();
     314           0 :             for (uint32_t i = 0; i < count; ++i)
     315           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     316           0 :             break;
     317             :           }
     318             :           case Scalar::Float64: {
     319           0 :             SharedMem<JS_VOLATILE_ARM double*> src = data.cast<JS_VOLATILE_ARM double*>();
     320           0 :             for (uint32_t i = 0; i < count; ++i)
     321           0 :                 Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
     322           0 :             break;
     323             :           }
     324             :           default:
     325           0 :             MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
     326             :         }
     327             : 
     328             : #undef JS_VOLATILE_ARM
     329             : 
     330           0 :         return true;
     331             :     }
     332             : 
     333             :     /*
     334             :      * Copy |source[0]| to |source[len]| (exclusive) elements into the typed
     335             :      * array |target|, starting at index |offset|.  |source| must not be a
     336             :      * typed array.
     337             :      */
     338             :     static bool
     339           0 :     setFromNonTypedArray(JSContext* cx, Handle<TypedArrayObject*> target, HandleObject source,
     340             :                          uint32_t len, uint32_t offset = 0)
     341             :     {
     342           0 :         MOZ_ASSERT(target->type() == TypeIDOfType<T>::id,
     343             :                    "target type and NativeType must match");
     344           0 :         MOZ_ASSERT(!target->hasDetachedBuffer(), "target isn't detached");
     345           0 :         MOZ_ASSERT(!source->is<TypedArrayObject>(),
     346             :                    "use setFromTypedArray instead of this method");
     347             : 
     348           0 :         uint32_t i = 0;
     349           0 :         if (source->isNative()) {
     350             :             // Attempt fast-path infallible conversion of dense elements up to
     351             :             // the first potentially side-effectful lookup or conversion.
     352           0 :             uint32_t bound = Min(source->as<NativeObject>().getDenseInitializedLength(), len);
     353             : 
     354           0 :             SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
     355             : 
     356           0 :             MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE)),
     357             :                        "the following loop must abort on holes");
     358             : 
     359           0 :             const Value* srcValues = source->as<NativeObject>().getDenseElements();
     360           0 :             for (; i < bound; i++) {
     361           0 :                 if (!canConvertInfallibly(srcValues[i]))
     362           0 :                     break;
     363           0 :                 Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
     364             :             }
     365           0 :             if (i == len)
     366           0 :                 return true;
     367             :         }
     368             : 
     369             :         // Convert and copy any remaining elements generically.
     370           0 :         RootedValue v(cx);
     371           0 :         for (; i < len; i++) {
     372           0 :             if (!GetElement(cx, source, source, i, &v))
     373           0 :                 return false;
     374             : 
     375           0 :             T n;
     376           0 :             if (!valueToNative(cx, v, &n))
     377           0 :                 return false;
     378             : 
     379           0 :             len = Min(len, target->length());
     380           0 :             if (i >= len)
     381           0 :                 break;
     382             : 
     383             :             // Compute every iteration in case getElement/valueToNative
     384             :             // detaches the underlying array buffer or GC moves the data.
     385           0 :             SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset + i;
     386           0 :             Ops::store(dest, n);
     387             :         }
     388             : 
     389           0 :         return true;
     390             :     }
     391             : 
     392             :     /*
     393             :      * Copy |source| into the typed array |target|.
     394             :      */
     395             :     static bool
     396           0 :     initFromIterablePackedArray(JSContext* cx, Handle<TypedArrayObject*> target,
     397             :                                 HandleArrayObject source)
     398             :     {
     399           0 :         MOZ_ASSERT(target->type() == TypeIDOfType<T>::id,
     400             :                    "target type and NativeType must match");
     401           0 :         MOZ_ASSERT(!target->hasDetachedBuffer(), "target isn't detached");
     402           0 :         MOZ_ASSERT(IsPackedArray(source), "source array must be packed");
     403           0 :         MOZ_ASSERT(source->getDenseInitializedLength() <= target->length());
     404             : 
     405           0 :         uint32_t len = source->getDenseInitializedLength();
     406           0 :         uint32_t i = 0;
     407             : 
     408             :         // Attempt fast-path infallible conversion of dense elements up to the
     409             :         // first potentially side-effectful conversion.
     410             : 
     411           0 :         SharedMem<T*> dest = target->viewDataEither().template cast<T*>();
     412             : 
     413           0 :         const Value* srcValues = source->getDenseElements();
     414           0 :         for (; i < len; i++) {
     415           0 :             if (!canConvertInfallibly(srcValues[i]))
     416           0 :                 break;
     417           0 :             Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
     418             :         }
     419           0 :         if (i == len)
     420           0 :             return true;
     421             : 
     422             :         // Convert any remaining elements by first collecting them into a
     423             :         // temporary list, and then copying them into the typed array.
     424           0 :         AutoValueVector values(cx);
     425           0 :         if (!values.append(srcValues + i, len - i))
     426           0 :             return false;
     427             : 
     428           0 :         RootedValue v(cx);
     429           0 :         for (uint32_t j = 0; j < values.length(); i++, j++) {
     430           0 :             v = values[j];
     431             : 
     432           0 :             T n;
     433           0 :             if (!valueToNative(cx, v, &n))
     434           0 :                 return false;
     435             : 
     436             :             // |target| is a newly allocated typed array and not yet visible to
     437             :             // content script, so valueToNative can't detach the underlying
     438             :             // buffer.
     439           0 :             MOZ_ASSERT(i < target->length());
     440             : 
     441             :             // Compute every iteration in case GC moves the data.
     442           0 :             SharedMem<T*> newDest = target->viewDataEither().template cast<T*>();
     443           0 :             Ops::store(newDest + i, n);
     444             :         }
     445             : 
     446           0 :         return true;
     447             :     }
     448             : 
     449             :   private:
     450             :     static bool
     451           0 :     setFromOverlappingTypedArray(JSContext* cx,
     452             :                                  Handle<TypedArrayObject*> target,
     453             :                                  Handle<TypedArrayObject*> source,
     454             :                                  uint32_t offset)
     455             :     {
     456             :         // WARNING: |source| may be an unwrapped typed array from a different
     457             :         // compartment. Proceed with caution!
     458             : 
     459           0 :         MOZ_ASSERT(TypeIDOfType<T>::id == target->type(),
     460             :                    "calling wrong setFromTypedArray specialization");
     461           0 :         MOZ_ASSERT(!target->hasDetachedBuffer(), "target isn't detached");
     462           0 :         MOZ_ASSERT(!source->hasDetachedBuffer(), "source isn't detached");
     463           0 :         MOZ_ASSERT(TypedArrayObject::sameBuffer(target, source),
     464             :                    "the provided arrays don't actually overlap, so it's "
     465             :                    "undesirable to use this method");
     466             : 
     467           0 :         MOZ_ASSERT(offset <= target->length());
     468           0 :         MOZ_ASSERT(source->length() <= target->length() - offset);
     469             : 
     470           0 :         SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
     471           0 :         uint32_t len = source->length();
     472             : 
     473           0 :         if (source->type() == target->type()) {
     474           0 :             SharedMem<T*> src = source->viewDataEither().template cast<T*>();
     475           0 :             Ops::podMove(dest, src, len);
     476           0 :             return true;
     477             :         }
     478             : 
     479             :         // Copy |source| in case it overlaps the target elements being set.
     480           0 :         size_t sourceByteLen = len * source->bytesPerElement();
     481           0 :         void* data = target->zone()->template pod_malloc<uint8_t>(sourceByteLen);
     482           0 :         if (!data)
     483           0 :             return false;
     484           0 :         Ops::memcpy(SharedMem<void*>::unshared(data),
     485           0 :                     source->viewDataEither(),
     486             :                     sourceByteLen);
     487             : 
     488           0 :         switch (source->type()) {
     489             :           case Scalar::Int8: {
     490           0 :             int8_t* src = static_cast<int8_t*>(data);
     491           0 :             for (uint32_t i = 0; i < len; ++i)
     492           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     493           0 :             break;
     494             :           }
     495             :           case Scalar::Uint8:
     496             :           case Scalar::Uint8Clamped: {
     497           0 :             uint8_t* src = static_cast<uint8_t*>(data);
     498           0 :             for (uint32_t i = 0; i < len; ++i)
     499           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     500           0 :             break;
     501             :           }
     502             :           case Scalar::Int16: {
     503           0 :             int16_t* src = static_cast<int16_t*>(data);
     504           0 :             for (uint32_t i = 0; i < len; ++i)
     505           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     506           0 :             break;
     507             :           }
     508             :           case Scalar::Uint16: {
     509           0 :             uint16_t* src = static_cast<uint16_t*>(data);
     510           0 :             for (uint32_t i = 0; i < len; ++i)
     511           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     512           0 :             break;
     513             :           }
     514             :           case Scalar::Int32: {
     515           0 :             int32_t* src = static_cast<int32_t*>(data);
     516           0 :             for (uint32_t i = 0; i < len; ++i)
     517           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     518           0 :             break;
     519             :           }
     520             :           case Scalar::Uint32: {
     521           0 :             uint32_t* src = static_cast<uint32_t*>(data);
     522           0 :             for (uint32_t i = 0; i < len; ++i)
     523           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     524           0 :             break;
     525             :           }
     526             :           case Scalar::Float32: {
     527           0 :             float* src = static_cast<float*>(data);
     528           0 :             for (uint32_t i = 0; i < len; ++i)
     529           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     530           0 :             break;
     531             :           }
     532             :           case Scalar::Float64: {
     533           0 :             double* src = static_cast<double*>(data);
     534           0 :             for (uint32_t i = 0; i < len; ++i)
     535           0 :                 Ops::store(dest++, ConvertNumber<T>(*src++));
     536           0 :             break;
     537             :           }
     538             :           default:
     539           0 :             MOZ_CRASH("setFromOverlappingTypedArray with a typed array with bogus type");
     540             :         }
     541             : 
     542           0 :         js_free(data);
     543           0 :         return true;
     544             :     }
     545             : 
     546             :     static bool
     547           0 :     canConvertInfallibly(const Value& v)
     548             :     {
     549           0 :         return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined();
     550             :     }
     551             : 
     552             :     static T
     553           0 :     infallibleValueToNative(const Value& v)
     554             :     {
     555           0 :         if (v.isInt32())
     556           0 :             return T(v.toInt32());
     557           0 :         if (v.isDouble())
     558           0 :             return doubleToNative(v.toDouble());
     559           0 :         if (v.isBoolean())
     560           0 :             return T(v.toBoolean());
     561           0 :         if (v.isNull())
     562           0 :             return T(0);
     563             : 
     564           0 :         MOZ_ASSERT(v.isUndefined());
     565           0 :         return TypeIsFloatingPoint<T>() ? T(JS::GenericNaN()) : T(0);
     566             :     }
     567             : 
     568             :     static bool
     569           0 :     valueToNative(JSContext* cx, HandleValue v, T* result)
     570             :     {
     571           0 :         MOZ_ASSERT(!v.isMagic());
     572             : 
     573           0 :         if (MOZ_LIKELY(canConvertInfallibly(v))) {
     574           0 :             *result = infallibleValueToNative(v);
     575           0 :             return true;
     576             :         }
     577             : 
     578             :         double d;
     579           0 :         MOZ_ASSERT(v.isString() || v.isObject() || v.isSymbol());
     580           0 :         if (!(v.isString() ? StringToNumber(cx, v.toString(), &d) : ToNumber(cx, v, &d)))
     581           0 :             return false;
     582             : 
     583           0 :         *result = doubleToNative(d);
     584           0 :         return true;
     585             :     }
     586             : 
     587             :     static T
     588           0 :     doubleToNative(double d)
     589             :     {
     590           0 :         if (TypeIsFloatingPoint<T>()) {
     591             : #ifdef JS_MORE_DETERMINISTIC
     592             :             // The JS spec doesn't distinguish among different NaN values, and
     593             :             // it deliberately doesn't specify the bit pattern written to a
     594             :             // typed array when NaN is written into it.  This bit-pattern
     595             :             // inconsistency could confuse deterministic testing, so always
     596             :             // canonicalize NaN values in more-deterministic builds.
     597             :             d = JS::CanonicalizeNaN(d);
     598             : #endif
     599           0 :             return T(d);
     600             :         }
     601           0 :         if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
     602           0 :             return T(0);
     603             :         if (TypeIDOfType<T>::id == Scalar::Uint8Clamped)
     604           0 :             return T(d);
     605           0 :         if (TypeIsUnsigned<T>())
     606           0 :             return T(JS::ToUint32(d));
     607           0 :         return T(JS::ToInt32(d));
     608             :     }
     609             : };
     610             : 
     611             : } // namespace js
     612             : 
     613             : #endif // vm_TypedArrayObject_inl_h

Generated by: LCOV version 1.13