Files
sdk/runtime/platform/utils.h
T
Alexander Markov 7a20b6b8d8 Option to truncate integers to 64 bits, part 1 (core VM changes)
This changeset revises --limit-ints-to-64-bits option to
change range of integers from unlimited to int64.
On overflow, integer arithmetic operations silently wrap around and
discard extra bits. No Bigints are allocated in case of overflow.

This changeset is the 1st part in the series of changes, it revises the implementation of integer arithmetic operations. More changes will follow.

R=regis@google.com, zra@google.com

Issue: https://github.com/dart-lang/sdk/issues/30103
Review-Url: https://codereview.chromium.org/2974633003 .
2017-07-10 15:16:40 -07:00

265 lines
7.8 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_PLATFORM_UTILS_H_
#define RUNTIME_PLATFORM_UTILS_H_
#include "platform/assert.h"
#include "platform/globals.h"
namespace dart {
class Utils {
public:
template <typename T>
static inline T Minimum(T x, T y) {
return x < y ? x : y;
}
template <typename T>
static inline T Maximum(T x, T y) {
return x > y ? x : y;
}
template <typename T>
static inline T Abs(T x) {
if (x < 0) return -x;
return x;
}
template <typename T>
static inline bool IsPowerOfTwo(T x) {
return ((x & (x - 1)) == 0) && (x != 0);
}
template <typename T>
static inline int ShiftForPowerOfTwo(T x) {
ASSERT(IsPowerOfTwo(x));
int num_shifts = 0;
while (x > 1) {
num_shifts++;
x = x >> 1;
}
return num_shifts;
}
template <typename T>
static inline bool IsAligned(T x, intptr_t n) {
ASSERT(IsPowerOfTwo(n));
return (x & (n - 1)) == 0;
}
template <typename T>
static inline bool IsAligned(T* x, intptr_t n) {
return IsAligned(reinterpret_cast<uword>(x), n);
}
template <typename T>
static inline T RoundDown(T x, intptr_t n) {
ASSERT(IsPowerOfTwo(n));
return (x & -n);
}
template <typename T>
static inline T* RoundDown(T* x, intptr_t n) {
return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uword>(x), n));
}
template <typename T>
static inline T RoundUp(T x, intptr_t n) {
return RoundDown(x + n - 1, n);
}
template <typename T>
static inline T* RoundUp(T* x, intptr_t n) {
return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uword>(x), n));
}
static uintptr_t RoundUpToPowerOfTwo(uintptr_t x);
static int CountOneBits(uint32_t x);
static int HighestBit(int64_t v);
static int BitLength(int64_t value) {
// Flip bits if negative (-1 becomes 0).
value ^= value >> (8 * sizeof(value) - 1);
return (value == 0) ? 0 : (Utils::HighestBit(value) + 1);
}
static int CountLeadingZeros(uword x);
static int CountTrailingZeros(uword x);
// Computes a hash value for the given string.
static uint32_t StringHash(const char* data, int length);
// Computes a hash value for the given word.
static uint32_t WordHash(intptr_t key);
// Check whether an N-bit two's-complement representation can hold value.
template <typename T>
static inline bool IsInt(int N, T value) {
ASSERT((0 < N) &&
(static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
T limit = static_cast<T>(1) << (N - 1);
return (-limit <= value) && (value < limit);
}
template <typename T>
static inline bool IsUint(int N, T value) {
ASSERT((0 < N) &&
(static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
T limit = static_cast<T>(1) << N;
return (0 <= value) && (value < limit);
}
// Check whether the magnitude of value fits in N bits, i.e., whether an
// (N+1)-bit sign-magnitude representation can hold value.
template <typename T>
static inline bool IsAbsoluteUint(int N, T value) {
ASSERT((0 < N) &&
(static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
if (value < 0) value = -value;
return IsUint(N, value);
}
static inline int32_t Low16Bits(int32_t value) {
return static_cast<int32_t>(value & 0xffff);
}
static inline int32_t High16Bits(int32_t value) {
return static_cast<int32_t>(value >> 16);
}
static inline int32_t Low32Bits(int64_t value) {
return static_cast<int32_t>(value);
}
static inline int32_t High32Bits(int64_t value) {
return static_cast<int32_t>(value >> 32);
}
static inline int64_t LowHighTo64Bits(uint32_t low, int32_t high) {
return (static_cast<int64_t>(high) << 32) | (low & 0x0ffffffffLL);
}
static bool IsDecimalDigit(char c) { return ('0' <= c) && (c <= '9'); }
static bool IsHexDigit(char c) {
return IsDecimalDigit(c) || (('A' <= c) && (c <= 'F')) ||
(('a' <= c) && (c <= 'f'));
}
static int HexDigitToInt(char c) {
ASSERT(IsHexDigit(c));
if (IsDecimalDigit(c)) return c - '0';
if (('A' <= c) && (c <= 'F')) return 10 + (c - 'A');
return 10 + (c - 'a');
}
static char IntToHexDigit(int i) {
ASSERT(0 <= i && i < 16);
if (i < 10) return static_cast<char>('0' + i);
return static_cast<char>('A' + (i - 10));
}
// Perform a range check, checking if
// offset + count <= length
// without the risk of integer overflow.
static inline bool RangeCheck(intptr_t offset,
intptr_t count,
intptr_t length) {
return offset >= 0 && count >= 0 && length >= 0 &&
count <= (length - offset);
}
static inline bool WillAddOverflow(int64_t a, int64_t b) {
return ((b > 0) && (a > (kMaxInt64 - b))) ||
((b < 0) && (a < (kMinInt64 - b)));
}
static inline bool WillSubOverflow(int64_t a, int64_t b) {
return ((b > 0) && (a < (kMinInt64 + b))) ||
((b < 0) && (a > (kMaxInt64 + b)));
}
// Adds two int64_t values with wrapping around
// (two's complement arithmetic).
static inline int64_t AddWithWrapAround(int64_t a, int64_t b) {
// Avoid undefined behavior by doing arithmetic in the unsigned type.
return static_cast<int64_t>(static_cast<uint64_t>(a) +
static_cast<uint64_t>(b));
}
// Subtracts two int64_t values with wrapping around
// (two's complement arithmetic).
static inline int64_t SubWithWrapAround(int64_t a, int64_t b) {
// Avoid undefined behavior by doing arithmetic in the unsigned type.
return static_cast<int64_t>(static_cast<uint64_t>(a) -
static_cast<uint64_t>(b));
}
// Multiplies two int64_t values with wrapping around
// (two's complement arithmetic).
static inline int64_t MulWithWrapAround(int64_t a, int64_t b) {
// Avoid undefined behavior by doing arithmetic in the unsigned type.
return static_cast<int64_t>(static_cast<uint64_t>(a) *
static_cast<uint64_t>(b));
}
// Shifts int64_t value left. Supports any non-negative number of bits and
// silently discards shifted out bits.
static inline int64_t ShiftLeftWithTruncation(int64_t a, int64_t b) {
ASSERT(b >= 0);
if (b >= kBitsPerInt64) {
return 0;
}
// Avoid undefined behavior by doing arithmetic in the unsigned type.
return static_cast<int64_t>(static_cast<uint64_t>(a) << b);
}
// Utility functions for converting values from host endianness to
// big or little endian values.
static uint16_t HostToBigEndian16(uint16_t host_value);
static uint32_t HostToBigEndian32(uint32_t host_value);
static uint64_t HostToBigEndian64(uint64_t host_value);
static uint16_t HostToLittleEndian16(uint16_t host_value);
static uint32_t HostToLittleEndian32(uint32_t host_value);
static uint64_t HostToLittleEndian64(uint64_t host_value);
static bool DoublesBitEqual(const double a, const double b) {
return bit_cast<int64_t, double>(a) == bit_cast<int64_t, double>(b);
}
// dart2js represents integers as double precision floats, which can
// represent anything in the range -2^53 ... 2^53.
static bool IsJavascriptInt(int64_t value) {
return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
}
static char* StrError(int err, char* buffer, size_t bufsize);
};
} // namespace dart
#if defined(HOST_OS_ANDROID)
#include "platform/utils_android.h"
#elif defined(HOST_OS_FUCHSIA)
#include "platform/utils_fuchsia.h"
#elif defined(HOST_OS_LINUX)
#include "platform/utils_linux.h"
#elif defined(HOST_OS_MACOS)
#include "platform/utils_macos.h"
#elif defined(HOST_OS_WINDOWS)
#include "platform/utils_win.h"
#else
#error Unknown target os.
#endif
#endif // RUNTIME_PLATFORM_UTILS_H_