diff --git a/src/utils.h b/src/utils.h index b2c2ff1098..90d7f3cdc6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -242,42 +242,52 @@ inline int StrLength(const char* string) { // ---------------------------------------------------------------------------- // BitField is a help template for encoding and decode bitfield with // unsigned content. -template -class BitField { + +template +class BitFieldBase { public: - // A uint32_t mask of bit field. To use all bits of a uint32 in a - // bitfield without compiler warnings we have to compute 2^32 without - // using a shift count of 32. - static const uint32_t kMask = ((1U << shift) << size) - (1U << shift); - static const uint32_t kShift = shift; - static const uint32_t kSize = size; + // A type U mask of bit field. To use all bits of a type U of x bits + // in a bitfield without compiler warnings we have to compute 2^x + // without using a shift count of x in the computation. + static const U kOne = static_cast(1U); + static const U kMask = ((kOne << shift) << size) - (kOne << shift); + static const U kShift = shift; + static const U kSize = size; // Value for the field with all bits set. static const T kMax = static_cast((1U << size) - 1); // Tells whether the provided value fits into the bit field. static bool is_valid(T value) { - return (static_cast(value) & ~static_cast(kMax)) == 0; + return (static_cast(value) & ~static_cast(kMax)) == 0; } - // Returns a uint32_t with the bit field value encoded. - static uint32_t encode(T value) { + // Returns a type U with the bit field value encoded. + static U encode(T value) { ASSERT(is_valid(value)); - return static_cast(value) << shift; + return static_cast(value) << shift; } - // Returns a uint32_t with the bit field value updated. - static uint32_t update(uint32_t previous, T value) { + // Returns a type U with the bit field value updated. + static U update(U previous, T value) { return (previous & ~kMask) | encode(value); } // Extracts the bit field from the value. - static T decode(uint32_t value) { + static T decode(U value) { return static_cast((value & kMask) >> shift); } }; +template +class BitField : public BitFieldBase { }; + + +template +class BitField64 : public BitFieldBase { }; + + // ---------------------------------------------------------------------------- // Hash function. diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 651dc59d58..398e832607 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -249,15 +249,13 @@ TEST(ExponentNumberStr) { CHECK_EQ(1e-106, StringToDouble(&uc, ".000001e-100", NO_FLAGS)); } -class OneBit1: public BitField {}; -class OneBit2: public BitField {}; -class EightBit1: public BitField {}; -class EightBit2: public BitField {}; TEST(BitField) { uint32_t x; // One bit bit field can hold values 0 and 1. + class OneBit1: public BitField {}; + class OneBit2: public BitField {}; CHECK(!OneBit1::is_valid(static_cast(-1))); CHECK(!OneBit2::is_valid(static_cast(-1))); for (int i = 0; i < 2; i++) { @@ -273,6 +271,8 @@ TEST(BitField) { CHECK(!OneBit2::is_valid(2)); // Eight bit bit field can hold values from 0 tp 255. + class EightBit1: public BitField {}; + class EightBit2: public BitField {}; CHECK(!EightBit1::is_valid(static_cast(-1))); CHECK(!EightBit2::is_valid(static_cast(-1))); for (int i = 0; i < 256; i++) { @@ -286,3 +286,20 @@ TEST(BitField) { CHECK(!EightBit1::is_valid(256)); CHECK(!EightBit2::is_valid(256)); } + + +TEST(BitField64) { + uint64_t x; + + // Test most significant bits. + class UpperBits: public BitField64 {}; + x = V8_2PART_UINT64_C(0xE0000000, 00000000); + CHECK(x == UpperBits::encode(7)); + CHECK_EQ(7, UpperBits::decode(x)); + + // Test the 32/64-bit boundary bits. + class MiddleBits: public BitField64 {}; + x = V8_2PART_UINT64_C(0x00000001, 80000000); + CHECK(x == MiddleBits::encode(3)); + CHECK_EQ(3, MiddleBits::decode(x)); +}