Backed out changeset a30cf37ddcab (bug 1447668) for build bustages at /builds/worker/workspace/build/src/js/src/ctypes/CTypes.cpp:2607 on a CLOSED TREE

--HG--
rename : js/src/jsapi-tests/testToSignedOrUnsignedInteger.cpp => js/src/jsapi-tests/testToIntWidth.cpp
This commit is contained in:
Andreea Pavel 2018-04-14 00:06:12 +03:00
Родитель 08cf6c4ee3
Коммит eb84122ef9
5 изменённых файлов: 186 добавлений и 222 удалений

Просмотреть файл

@ -286,25 +286,27 @@ ToObject(JSContext* cx, HandleValue v)
return js::ToObjectSlow(cx, v, false);
}
/**
* Convert a double value to UnsignedInteger (an unsigned integral type) using
namespace detail {
/*
* Convert a double value to ResultType (an unsigned integral type) using
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
* ToInt32 converts to int32_t).
*
* If d is infinite or NaN, return 0.
* Otherwise compute d2 = sign(d) * floor(abs(d)), and return the
* UnsignedInteger value congruent to d2 % 2**(bit width of UnsignedInteger).
* Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType
* value congruent to d2 mod 2**(bit width of ResultType).
*
* The algorithm below is inspired by that found in
* <https://trac.webkit.org/changeset/67825/webkit/trunk/JavaScriptCore/runtime/JSValue.cpp>
* <http://trac.webkit.org/changeset/67825/trunk/JavaScriptCore/runtime/JSValue.cpp>
* but has been generalized to all integer widths.
*/
template<typename UnsignedInteger>
inline UnsignedInteger
ToUnsignedInteger(double d)
template<typename ResultType>
inline ResultType
ToUintWidth(double d)
{
static_assert(mozilla::IsUnsigned<UnsignedInteger>::value,
"UnsignedInteger must be an unsigned type");
static_assert(mozilla::IsUnsigned<ResultType>::value,
"ResultType must be an unsigned type");
uint64_t bits = mozilla::BitwiseCast<uint64_t>(d);
unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::kExponentShift;
@ -323,23 +325,23 @@ ToUnsignedInteger(double d)
uint_fast16_t exponent = mozilla::AssertedCast<uint_fast16_t>(exp);
// If the exponent is greater than or equal to the bits of precision of a
// double plus UnsignedInteger's width, the number is either infinite, NaN,
// or too large to have lower-order bits in the congruent value. (Example:
// double plus ResultType's width, the number is either infinite, NaN, or
// too large to have lower-order bits in the congruent value. (Example:
// 2**84 is exactly representable as a double. The next exact double is
// 2**84 + 2**32. Thus if UnsignedInteger is uint32_t, an exponent >= 84
// implies floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases.
constexpr size_t ResultWidth = CHAR_BIT * sizeof(UnsignedInteger);
// 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies
// floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases.
const size_t ResultWidth = CHAR_BIT * sizeof(ResultType);
if (exponent >= DoubleExponentShift + ResultWidth)
return 0;
// The significand contains the bits that will determine the final result.
// Shift those bits left or right, according to the exponent, to their
// locations in the unsigned binary representation of floor(abs(d)).
static_assert(sizeof(UnsignedInteger) <= sizeof(uint64_t),
"left-shifting below would lose upper bits");
UnsignedInteger result = (exponent > DoubleExponentShift)
? UnsignedInteger(bits << (exponent - DoubleExponentShift))
: UnsignedInteger(bits >> (DoubleExponentShift - exponent));
static_assert(sizeof(ResultType) <= sizeof(uint64_t),
"Left-shifting below would lose upper bits");
ResultType result = (exponent > DoubleExponentShift)
? ResultType(bits << (exponent - DoubleExponentShift))
: ResultType(bits >> (DoubleExponentShift - exponent));
// Two further complications remain. First, |result| may contain bogus
// sign/exponent bits. Second, IEEE-754 numbers' significands (excluding
@ -366,7 +368,7 @@ ToUnsignedInteger(double d)
// The implicit leading bit matters identically to the other case, so
// again, |exponent < ResultWidth|.
if (exponent < ResultWidth) {
UnsignedInteger implicitOne = UnsignedInteger(1) << exponent;
ResultType implicitOne = ResultType(1) << exponent;
result &= implicitOne - 1; // remove bogus bits
result += implicitOne; // add the implicit bit
}
@ -375,27 +377,28 @@ ToUnsignedInteger(double d)
return (bits & mozilla::FloatingPoint<double>::kSignBit) ? ~result + 1 : result;
}
template<typename SignedInteger>
inline SignedInteger
ToSignedInteger(double d)
template<typename ResultType>
inline ResultType
ToIntWidth(double d)
{
static_assert(mozilla::IsSigned<SignedInteger>::value,
"SignedInteger must be a signed type");
static_assert(mozilla::IsSigned<ResultType>::value,
"ResultType must be a signed type");
using UnsignedInteger = typename mozilla::MakeUnsigned<SignedInteger>::Type;
UnsignedInteger u = ToUnsignedInteger<UnsignedInteger>(d);
using UnsignedResult = typename mozilla::MakeUnsigned<ResultType>::Type;
UnsignedResult u = ToUintWidth<UnsignedResult>(d);
return mozilla::WrapToSigned(u);
}
// clang crashes compiling this when targeting arm:
// https://llvm.org/bugs/show_bug.cgi?id=22974
#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__)
} // namespace detail
template<>
/* ES5 9.5 ToInt32 (specialized for doubles). */
inline int32_t
ToSignedInteger<int32_t>(double d)
ToInt32(double d)
{
// clang crashes compiling this when targeting arm:
// https://llvm.org/bugs/show_bug.cgi?id=22974
#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__)
int32_t i;
uint32_t tmp0;
uint32_t tmp1;
@ -516,94 +519,57 @@ ToSignedInteger<int32_t>(double d)
: "cc"
);
return i;
}
#endif // defined (__arm__) && defined (__GNUC__) && !defined(__clang__)
namespace detail {
template<typename IntegerType,
bool IsUnsigned = mozilla::IsUnsigned<IntegerType>::value>
struct ToSignedOrUnsignedInteger;
template<typename IntegerType>
struct ToSignedOrUnsignedInteger<IntegerType, true>
{
static IntegerType compute(double d) {
return ToUnsignedInteger<IntegerType>(d);
}
};
template<typename IntegerType>
struct ToSignedOrUnsignedInteger<IntegerType, false>
{
static IntegerType compute(double d) {
return ToSignedInteger<IntegerType>(d);
}
};
} // namespace detail
template<typename IntegerType>
inline IntegerType
ToSignedOrUnsignedInteger(double d)
{
return detail::ToSignedOrUnsignedInteger<IntegerType>::compute(d);
}
/* WEBIDL 4.2.4 */
inline int8_t
ToInt8(double d)
{
return ToSignedInteger<int8_t>(d);
}
/* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */
inline int8_t
ToUint8(double d)
{
return ToUnsignedInteger<uint8_t>(d);
}
/* WEBIDL 4.2.6 */
inline int16_t
ToInt16(double d)
{
return ToSignedInteger<int16_t>(d);
}
inline uint16_t
ToUint16(double d)
{
return ToUnsignedInteger<uint16_t>(d);
}
/* ES5 9.5 ToInt32 (specialized for doubles). */
inline int32_t
ToInt32(double d)
{
return ToSignedInteger<int32_t>(d);
#else
return detail::ToIntWidth<int32_t>(d);
#endif
}
/* ES5 9.6 (specialized for doubles). */
inline uint32_t
ToUint32(double d)
{
return ToUnsignedInteger<uint32_t>(d);
return detail::ToUintWidth<uint32_t>(d);
}
/* WEBIDL 4.2.4 */
inline int8_t
ToInt8(double d)
{
return detail::ToIntWidth<int8_t>(d);
}
/* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */
inline int8_t
ToUint8(double d)
{
return detail::ToUintWidth<uint8_t>(d);
}
/* WEBIDL 4.2.6 */
inline int16_t
ToInt16(double d)
{
return detail::ToIntWidth<int16_t>(d);
}
inline uint16_t
ToUint16(double d)
{
return detail::ToUintWidth<uint16_t>(d);
}
/* WEBIDL 4.2.10 */
inline int64_t
ToInt64(double d)
{
return ToSignedInteger<int64_t>(d);
return detail::ToIntWidth<int64_t>(d);
}
/* WEBIDL 4.2.11 */
inline uint64_t
ToUint64(double d)
{
return ToUnsignedInteger<uint64_t>(d);
return detail::ToUintWidth<uint64_t>(d);
}
} // namespace JS

Просмотреть файл

@ -11,24 +11,22 @@
#include "mozilla/Sprintf.h"
#include "mozilla/TextUtils.h"
#include "mozilla/Vector.h"
#include "mozilla/WrappingOperations.h"
#if defined(XP_UNIX)
# include <errno.h>
#endif
#include <limits>
#include <math.h>
#include <stdint.h>
#if defined(XP_WIN)
# include <float.h>
#endif
#if defined(SOLARIS)
# include <ieeefp.h>
#endif
#include <limits>
#include <math.h>
#include <stdint.h>
#ifdef HAVE_SSIZE_T
# include <sys/types.h>
#endif
#include <type_traits>
#if defined(XP_UNIX)
# include <errno.h>
#endif
#include "jsexn.h"
#include "jsnum.h"
@ -2582,52 +2580,54 @@ JS_STATIC_ASSERT(sizeof(float) == 4);
JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
JS_STATIC_ASSERT(numeric_limits<double>::is_signed);
template<typename TargetType,
typename FromType,
bool FromIsIntegral = std::is_integral<FromType>::value>
struct ConvertImpl;
template<typename TargetType, typename FromType>
struct ConvertImpl<TargetType, FromType, false>
{
static MOZ_ALWAYS_INLINE TargetType Convert(FromType input) {
return JS::ToSignedOrUnsignedInteger<TargetType>(input);
// Templated helper to convert FromType to TargetType, for the default case
// where the trivial POD constructor will do.
template<class TargetType, class FromType>
struct ConvertImpl {
static MOZ_ALWAYS_INLINE TargetType Convert(FromType d) {
return TargetType(d);
}
};
template<typename TargetType>
inline TargetType
ConvertUnsignedTargetTo(typename std::make_unsigned<TargetType>::type input)
{
return std::is_signed<TargetType>::value ? mozilla::WrapToSigned(input) : input;
}
#ifdef _MSC_VER
// MSVC can't perform double to unsigned __int64 conversion when the
// double is greater than 2^63 - 1. Help it along a little.
template<>
struct ConvertImpl<uint64_t, double> {
static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
return d > 0x7fffffffffffffffui64 ?
uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
uint64_t(d);
}
};
#endif
// C++ doesn't guarantee that exact values are the only ones that will
// round-trip. In fact, on some platforms, including SPARC, there are pairs of
// values, a uint64_t and a double, such that neither value is exactly
// representable in the other type, but they cast to each other.
#if defined(SPARC) || defined(__powerpc__)
// Simulate x86 overflow behavior
template<>
struct ConvertImpl<uint64_t, double> {
static MOZ_ALWAYS_INLINE uint64_t Convert(double d) {
return d >= 0xffffffffffffffff ?
0x8000000000000000 : uint64_t(d);
}
};
template<>
inline char16_t
ConvertUnsignedTargetTo<char16_t>(char16_t input)
{
// mozilla::WrapToSigned can't be used on char16_t.
return input;
}
template<typename TargetType, typename FromType>
struct ConvertImpl<TargetType, FromType, true>
{
static MOZ_ALWAYS_INLINE TargetType Convert(FromType input) {
using UnsignedTargetType = typename std::make_unsigned<TargetType>::type;
auto resultUnsigned = static_cast<UnsignedTargetType>(input);
return ConvertUnsignedTargetTo<TargetType>(resultUnsigned);
struct ConvertImpl<int64_t, double> {
static MOZ_ALWAYS_INLINE int64_t Convert(double d) {
return d >= 0x7fffffffffffffff ?
0x8000000000000000 : int64_t(d);
}
};
#endif
template<class TargetType, class FromType>
static MOZ_ALWAYS_INLINE TargetType Convert(FromType d)
{
static_assert(std::is_integral<FromType>::value !=
std::is_floating_point<FromType>::value,
"should only be converting from floating/integral type");
return ConvertImpl<TargetType, FromType>::Convert(d);
}
@ -2690,8 +2690,8 @@ struct IsExactImpl<TargetType, FromType, true, false> {
template<class TargetType, class FromType>
static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
{
static_assert(std::numeric_limits<TargetType>::is_exact,
"TargetType must be exact to simplify conversion");
// Require that TargetType is integral, to simplify conversion.
JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
*result = Convert<TargetType>(i);
@ -3106,11 +3106,9 @@ jsvalToIntegerExplicit(HandleValue val, IntegerType* result)
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
if (val.isDouble()) {
// Convert using ToInt32-style semantics: non-finite numbers become 0, and
// everything else rounds toward zero then maps into |IntegerType| with
// wraparound semantics.
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
double d = val.toDouble();
*result = JS::ToSignedOrUnsignedInteger<IntegerType>(d);
*result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
return true;
}
if (val.isObject()) {

Просмотреть файл

@ -99,7 +99,7 @@ UNIFIED_SOURCES += [
'testThreadingExclusiveData.cpp',
'testThreadingMutex.cpp',
'testThreadingThread.cpp',
'testToSignedOrUnsignedInteger.cpp',
'testToIntWidth.cpp',
'testTypedArrays.cpp',
'testUbiNode.cpp',
'testUncaughtSymbol.cpp',

Просмотреть файл

@ -0,0 +1,69 @@
/* -*- 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/. */
#include <math.h>
#include "js/Conversions.h"
#include "jsapi-tests/tests.h"
using JS::detail::ToIntWidth;
using JS::detail::ToUintWidth;
BEGIN_TEST(testToUint8TwiceUint8Range)
{
double d = -256;
uint8_t expected = 0;
do {
CHECK(ToUintWidth<uint8_t>(d) == expected);
d++;
expected++;
} while (d <= 256);
return true;
}
END_TEST(testToUint8TwiceUint8Range)
BEGIN_TEST(testToInt8)
{
double d = -128;
int8_t expected = -128;
do {
CHECK(ToIntWidth<int8_t>(d) == expected);
d++;
expected++;
} while (expected < 127);
return true;
}
END_TEST(testToInt8)
BEGIN_TEST(testToUint32Large)
{
CHECK(ToUintWidth<uint32_t>(pow(2.0, 83)) == 0);
CHECK(ToUintWidth<uint32_t>(pow(2.0, 83) + pow(2.0, 31)) == (1U << 31));
CHECK(ToUintWidth<uint32_t>(pow(2.0, 83) + 2 * pow(2.0, 31)) == 0);
CHECK(ToUintWidth<uint32_t>(pow(2.0, 83) + 3 * pow(2.0, 31)) == (1U << 31));
CHECK(ToUintWidth<uint32_t>(pow(2.0, 84)) == 0);
CHECK(ToUintWidth<uint32_t>(pow(2.0, 84) + pow(2.0, 31)) == 0);
CHECK(ToUintWidth<uint32_t>(pow(2.0, 84) + pow(2.0, 32)) == 0);
return true;
}
END_TEST(testToUint32Large)
BEGIN_TEST(testToUint64Large)
{
CHECK(ToUintWidth<uint64_t>(pow(2.0, 115)) == 0);
CHECK(ToUintWidth<uint64_t>(pow(2.0, 115) + pow(2.0, 63)) == (1ULL << 63));
CHECK(ToUintWidth<uint64_t>(pow(2.0, 115) + 2 * pow(2.0, 63)) == 0);
CHECK(ToUintWidth<uint64_t>(pow(2.0, 115) + 3 * pow(2.0, 63)) == (1ULL << 63));
CHECK(ToUintWidth<uint64_t>(pow(2.0, 116)) == 0);
CHECK(ToUintWidth<uint64_t>(pow(2.0, 116) + pow(2.0, 63)) == 0);
CHECK(ToUintWidth<uint64_t>(pow(2.0, 116) + pow(2.0, 64)) == 0);
return true;
}
END_TEST(testToUint64Large)

Просмотреть файл

@ -1,69 +0,0 @@
/* -*- 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/. */
#include <math.h>
#include "js/Conversions.h"
#include "jsapi-tests/tests.h"
using JS::ToSignedInteger;
using JS::ToUnsignedInteger;
BEGIN_TEST(testToUint8TwiceUint8Range)
{
double d = -256;
uint8_t expected = 0;
do {
CHECK(ToUnsignedInteger<uint8_t>(d) == expected);
d++;
expected++;
} while (d <= 256);
return true;
}
END_TEST(testToUint8TwiceUint8Range)
BEGIN_TEST(testToInt8)
{
double d = -128;
int8_t expected = -128;
do {
CHECK(ToSignedInteger<int8_t>(d) == expected);
d++;
expected++;
} while (expected < 127);
return true;
}
END_TEST(testToInt8)
BEGIN_TEST(testToUint32Large)
{
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 83)) == 0);
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 83) + pow(2.0, 31)) == (1U << 31));
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 83) + 2 * pow(2.0, 31)) == 0);
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 83) + 3 * pow(2.0, 31)) == (1U << 31));
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 84)) == 0);
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 84) + pow(2.0, 31)) == 0);
CHECK(ToUnsignedInteger<uint32_t>(pow(2.0, 84) + pow(2.0, 32)) == 0);
return true;
}
END_TEST(testToUint32Large)
BEGIN_TEST(testToUint64Large)
{
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 115)) == 0);
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 115) + pow(2.0, 63)) == (1ULL << 63));
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 115) + 2 * pow(2.0, 63)) == 0);
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 115) + 3 * pow(2.0, 63)) == (1ULL << 63));
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 116)) == 0);
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 116) + pow(2.0, 63)) == 0);
CHECK(ToUnsignedInteger<uint64_t>(pow(2.0, 116) + pow(2.0, 64)) == 0);
return true;
}
END_TEST(testToUint64Large)