Commit db0c86fa authored by clemensh's avatar clemensh Committed by Commit bot

[base] Define CHECK comparison for signed vs. unsigned

The current CHECK/DCHECK implementation fails statically if a signed
value is compared against an unsigned value. The common solution is to
cast on each caller, which is tedious and error-prone (might hide bugs).
This CL implements signed vs. unsigned comparisons by executing up to
two comparisons. For example, if i is int32_t and u is uint_32_t, a
DCHECK_LE(i, u) would create the check
i <= 0 || static_cast<uint32_t>(i) <= u.
For checks against constants, at least one of the checks can be removed
by compiler optimizations.

The tradeoff we have to make is to sometimes silently execute an
additional comparison. And we increase code complexity of course, even
though the usage is just as easy (or even easier) as before.

The compile time impact seems to be minimal:
I ran 3 full compilations for Optdebug on my local machine, one time on
the current ToT, one time with this CL plus http://crrev.com/2524093002.
Before: 143.72 +- 1.21 seconds
Now: 144.18 +- 0.67 seconds

In order to check that the new comparisons are working, I refactored
some DCHECKs in wasm to use the new magic, and added unit test cases.

R=ishell@chromium.org, titzer@chromium.org
CC=ahaas@chromium.org, bmeurer@chromium.org

Committed: https://crrev.com/5925074a9dab5a8577766545b91b62f2c531d3dc
Review-Url: https://codereview.chromium.org/2526783002
Cr-Original-Commit-Position: refs/heads/master@{#41275}
Cr-Commit-Position: refs/heads/master@{#41411}
parent c71fc990
...@@ -111,16 +111,72 @@ DEFINE_MAKE_CHECK_OP_STRING(char const*) ...@@ -111,16 +111,72 @@ DEFINE_MAKE_CHECK_OP_STRING(char const*)
DEFINE_MAKE_CHECK_OP_STRING(void const*) DEFINE_MAKE_CHECK_OP_STRING(void const*)
#undef DEFINE_MAKE_CHECK_OP_STRING #undef DEFINE_MAKE_CHECK_OP_STRING
// is_signed_vs_unsigned::value is true if both types are integral, Lhs is
// signed, and Rhs is unsigned. False in all other cases.
template <typename Lhs, typename Rhs>
struct is_signed_vs_unsigned {
enum : bool {
value = std::is_integral<Lhs>::value && std::is_integral<Rhs>::value &&
std::is_signed<Lhs>::value && std::is_unsigned<Rhs>::value
};
};
// Same thing, other way around: Lhs is unsigned, Rhs signed.
template <typename Lhs, typename Rhs>
struct is_unsigned_vs_signed : public is_signed_vs_unsigned<Rhs, Lhs> {};
// Specialize the compare functions for signed vs. unsigned comparisons.
// std::enable_if ensures that this template is only instantiable if both Lhs
// and Rhs are integral types, and their signedness does not match.
#define MAKE_UNSIGNED(Type, value) \
static_cast<typename std::make_unsigned<Type>::type>(value)
#define DEFINE_SIGNED_MISMATCH_COMP(CHECK, NAME, IMPL) \
template <typename Lhs, typename Rhs> \
V8_INLINE typename std::enable_if<CHECK<Lhs, Rhs>::value, bool>::type \
Cmp##NAME##Impl(Lhs const& lhs, Rhs const& rhs) { \
return IMPL; \
}
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, EQ,
lhs >= 0 && MAKE_UNSIGNED(Lhs, lhs) == rhs)
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LT,
lhs < 0 || MAKE_UNSIGNED(Lhs, lhs) < rhs)
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LE,
lhs <= 0 || MAKE_UNSIGNED(Lhs, lhs) <= rhs)
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, NE, !CmpEQImpl(lhs, rhs))
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GT, !CmpLEImpl(lhs, rhs))
DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GE, !CmpLTImpl(lhs, rhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, EQ, CmpEQImpl(rhs, lhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, NE, CmpNEImpl(rhs, lhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LT, CmpGTImpl(rhs, lhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LE, CmpGEImpl(rhs, lhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GT, CmpLTImpl(rhs, lhs))
DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GE, CmpLEImpl(rhs, lhs))
#undef MAKE_UNSIGNED
#undef DEFINE_SIGNED_MISMATCH_COMP
// Helper functions for CHECK_OP macro. // Helper functions for CHECK_OP macro.
// The (float, float) and (double, double) instantiations are explicitly // The (float, float) and (double, double) instantiations are explicitly
// externialized to ensure proper 32/64-bit comparisons on x86. // externalized to ensure proper 32/64-bit comparisons on x86.
// The Cmp##NAME##Impl function is only instantiable if one of the two types is
// not integral or their signedness matches (i.e. whenever no specialization is
// required, see above). Otherwise it is disabled by the enable_if construct,
// and the compiler will pick a specialization from above.
#define DEFINE_CHECK_OP_IMPL(NAME, op) \ #define DEFINE_CHECK_OP_IMPL(NAME, op) \
template <typename Lhs, typename Rhs> \
V8_INLINE \
typename std::enable_if<!is_signed_vs_unsigned<Lhs, Rhs>::value && \
!is_unsigned_vs_signed<Lhs, Rhs>::value, \
bool>::type \
Cmp##NAME##Impl(typename PassType<Lhs>::type lhs, \
typename PassType<Rhs>::type rhs) { \
return lhs op rhs; \
} \
template <typename Lhs, typename Rhs> \ template <typename Lhs, typename Rhs> \
V8_INLINE std::string* Check##NAME##Impl(typename PassType<Lhs>::type lhs, \ V8_INLINE std::string* Check##NAME##Impl(typename PassType<Lhs>::type lhs, \
typename PassType<Rhs>::type rhs, \ typename PassType<Rhs>::type rhs, \
char const* msg) { \ char const* msg) { \
return V8_LIKELY(lhs op rhs) ? nullptr \ bool cmp = Cmp##NAME##Impl<Lhs, Rhs>(lhs, rhs); \
: MakeCheckOpString<Lhs, Rhs>(lhs, rhs, msg); \ return V8_LIKELY(cmp) ? nullptr \
: MakeCheckOpString<Lhs, Rhs>(lhs, rhs, msg); \
} \ } \
extern template V8_BASE_EXPORT std::string* Check##NAME##Impl<float, float>( \ extern template V8_BASE_EXPORT std::string* Check##NAME##Impl<float, float>( \
float lhs, float rhs, char const* msg); \ float lhs, float rhs, char const* msg); \
......
...@@ -110,9 +110,9 @@ class Log { ...@@ -110,9 +110,9 @@ class Log {
// Implementation of writing to a log file. // Implementation of writing to a log file.
int WriteToFile(const char* msg, int length) { int WriteToFile(const char* msg, int length) {
DCHECK(output_handle_ != NULL); DCHECK_NOT_NULL(output_handle_);
size_t rv = fwrite(msg, 1, length, output_handle_); size_t rv = fwrite(msg, 1, length, output_handle_);
DCHECK(static_cast<size_t>(length) == rv); DCHECK_EQ(length, rv);
USE(rv); USE(rv);
fflush(output_handle_); fflush(output_handle_);
return length; return length;
......
...@@ -88,7 +88,7 @@ struct MergeValues { ...@@ -88,7 +88,7 @@ struct MergeValues {
} vals; // Either multiple values or a single value. } vals; // Either multiple values or a single value.
Value& first() { Value& first() {
DCHECK_GT(arity, 0u); DCHECK_GT(arity, 0);
return arity == 1 ? vals.first : vals.array[0]; return arity == 1 ? vals.first : vals.array[0];
} }
}; };
...@@ -577,7 +577,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -577,7 +577,7 @@ class WasmFullDecoder : public WasmDecoder {
// Decodes the locals declarations, if any, populating {local_type_vec_}. // Decodes the locals declarations, if any, populating {local_type_vec_}.
void DecodeLocalDecls() { void DecodeLocalDecls() {
DCHECK_EQ(0u, local_type_vec_.size()); DCHECK_EQ(0, local_type_vec_.size());
// Initialize {local_type_vec} from signature. // Initialize {local_type_vec} from signature.
if (sig_) { if (sig_) {
local_type_vec_.reserve(sig_->parameter_count()); local_type_vec_.reserve(sig_->parameter_count());
...@@ -1443,7 +1443,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1443,7 +1443,7 @@ class WasmFullDecoder : public WasmDecoder {
Value val = {pc_, nullptr, kAstStmt}; Value val = {pc_, nullptr, kAstStmt};
return val; return val;
} else { } else {
DCHECK_LE(stack_depth, static_cast<int>(stack_.size())); DCHECK_LE(stack_depth, stack_.size());
Value val = Pop(); Value val = Pop();
stack_.resize(stack_depth); stack_.resize(stack_depth);
return val; return val;
......
...@@ -1171,7 +1171,7 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1171,7 +1171,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
} }
bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) { bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) {
DCHECK_GT(frames_.size(), 0u); DCHECK_GT(frames_.size(), 0);
// Pop all blocks for this frame. // Pop all blocks for this frame.
while (!blocks_.empty() && blocks_.back().fp == frames_.size()) { while (!blocks_.empty() && blocks_.back().fp == frames_.size()) {
blocks_.pop_back(); blocks_.pop_back();
...@@ -1678,8 +1678,8 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1678,8 +1678,8 @@ class ThreadImpl : public WasmInterpreter::Thread {
} }
WasmVal Pop() { WasmVal Pop() {
DCHECK_GT(stack_.size(), 0u); DCHECK_GT(stack_.size(), 0);
DCHECK_GT(frames_.size(), 0u); DCHECK_GT(frames_.size(), 0);
DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals DCHECK_GT(stack_.size(), frames_.back().llimit()); // can't pop into locals
WasmVal val = stack_.back(); WasmVal val = stack_.back();
stack_.pop_back(); stack_.pop_back();
...@@ -1687,8 +1687,8 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1687,8 +1687,8 @@ class ThreadImpl : public WasmInterpreter::Thread {
} }
void PopN(int n) { void PopN(int n) {
DCHECK_GE(stack_.size(), static_cast<size_t>(n)); DCHECK_GE(stack_.size(), n);
DCHECK_GT(frames_.size(), 0u); DCHECK_GT(frames_.size(), 0);
size_t nsize = stack_.size() - n; size_t nsize = stack_.size() - n;
DCHECK_GE(nsize, frames_.back().llimit()); // can't pop into locals DCHECK_GE(nsize, frames_.back().llimit()); // can't pop into locals
stack_.resize(nsize); stack_.resize(nsize);
...@@ -1696,7 +1696,7 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1696,7 +1696,7 @@ class ThreadImpl : public WasmInterpreter::Thread {
WasmVal PopArity(size_t arity) { WasmVal PopArity(size_t arity) {
if (arity == 0) return WasmVal(); if (arity == 0) return WasmVal();
CHECK_EQ(1u, arity); CHECK_EQ(1, arity);
return Pop(); return Pop();
} }
......
...@@ -52,8 +52,8 @@ MaybeHandle<String> ExtractStringFromModuleBytes( ...@@ -52,8 +52,8 @@ MaybeHandle<String> ExtractStringFromModuleBytes(
uint32_t offset, uint32_t size) { uint32_t offset, uint32_t size) {
// TODO(wasm): cache strings from modules if it's a performance win. // TODO(wasm): cache strings from modules if it's a performance win.
Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes(); Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
DCHECK_GE(static_cast<size_t>(module_bytes->length()), offset); DCHECK_GE(module_bytes->length(), offset);
DCHECK_GE(static_cast<size_t>(module_bytes->length() - offset), size); DCHECK_GE(module_bytes->length() - offset, size);
Address raw = module_bytes->GetCharsAddress() + offset; Address raw = module_bytes->GetCharsAddress() + offset;
if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size)) if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
return {}; // UTF8 decoding error for name. return {}; // UTF8 decoding error for name.
...@@ -111,7 +111,7 @@ void* TryAllocateBackingStore(Isolate* isolate, size_t size, ...@@ -111,7 +111,7 @@ void* TryAllocateBackingStore(Isolate* isolate, size_t size,
// addressable memory after the guard page can be made inaccessible. // addressable memory after the guard page can be made inaccessible.
const size_t alloc_size = const size_t alloc_size =
RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()); RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize());
DCHECK_EQ(0u, size % base::OS::CommitPageSize()); DCHECK_EQ(0, size % base::OS::CommitPageSize());
// AllocateGuarded makes the whole region inaccessible by default. // AllocateGuarded makes the whole region inaccessible by default.
void* memory = base::OS::AllocateGuarded(alloc_size); void* memory = base::OS::AllocateGuarded(alloc_size);
...@@ -2074,7 +2074,7 @@ MaybeHandle<WasmModuleObject> wasm::CreateModuleObjectFromBytes( ...@@ -2074,7 +2074,7 @@ MaybeHandle<WasmModuleObject> wasm::CreateModuleObjectFromBytes(
compiled_module->set_script(asm_js_script); compiled_module->set_script(asm_js_script);
size_t offset_table_len = size_t offset_table_len =
asm_js_offset_tables_end - asm_js_offset_tables_start; asm_js_offset_tables_end - asm_js_offset_tables_start;
DCHECK_GE(static_cast<size_t>(kMaxInt), offset_table_len); DCHECK_GE(kMaxInt, offset_table_len);
Handle<ByteArray> offset_table = Handle<ByteArray> offset_table =
isolate->factory()->NewByteArray(static_cast<int>(offset_table_len)); isolate->factory()->NewByteArray(static_cast<int>(offset_table_len));
memcpy(offset_table->GetDataStartAddress(), asm_js_offset_tables_start, memcpy(offset_table->GetDataStartAddress(), asm_js_offset_tables_start,
......
...@@ -277,7 +277,7 @@ struct V8_EXPORT_PRIVATE ModuleWireBytes { ...@@ -277,7 +277,7 @@ struct V8_EXPORT_PRIVATE ModuleWireBytes {
WasmName GetName(uint32_t offset, uint32_t length) const { WasmName GetName(uint32_t offset, uint32_t length) const {
if (length == 0) return {"<?>", 3}; // no name. if (length == 0) return {"<?>", 3}; // no name.
CHECK(BoundsCheck(offset, length)); CHECK(BoundsCheck(offset, length));
DCHECK_GE(static_cast<int>(length), 0); DCHECK_GE(length, 0);
return Vector<const char>::cast( return Vector<const char>::cast(
module_bytes.SubVector(offset, offset + length)); module_bytes.SubVector(offset, offset + length));
} }
...@@ -291,7 +291,7 @@ struct V8_EXPORT_PRIVATE ModuleWireBytes { ...@@ -291,7 +291,7 @@ struct V8_EXPORT_PRIVATE ModuleWireBytes {
WasmName GetNameOrNull(uint32_t offset, uint32_t length) const { WasmName GetNameOrNull(uint32_t offset, uint32_t length) const {
if (offset == 0 && length == 0) return {NULL, 0}; // no name. if (offset == 0 && length == 0) return {NULL, 0}; // no name.
CHECK(BoundsCheck(offset, length)); CHECK(BoundsCheck(offset, length));
DCHECK_GE(static_cast<int>(length), 0); DCHECK_GE(length, 0);
return Vector<const char>::cast( return Vector<const char>::cast(
module_bytes.SubVector(offset, offset + length)); module_bytes.SubVector(offset, offset + length));
} }
......
...@@ -51,7 +51,7 @@ static uint32_t SafeUint32(Object* value) { ...@@ -51,7 +51,7 @@ static uint32_t SafeUint32(Object* value) {
DCHECK(value->IsHeapNumber()); DCHECK(value->IsHeapNumber());
HeapNumber* num = HeapNumber::cast(value); HeapNumber* num = HeapNumber::cast(value);
CHECK_GE(num->value(), 0.0); CHECK_GE(num->value(), 0.0);
CHECK_LE(num->value(), static_cast<double>(kMaxUInt32)); CHECK_LE(num->value(), kMaxUInt32);
return static_cast<uint32_t>(num->value()); return static_cast<uint32_t>(num->value());
} }
...@@ -61,8 +61,8 @@ static int32_t SafeInt32(Object* value) { ...@@ -61,8 +61,8 @@ static int32_t SafeInt32(Object* value) {
} }
DCHECK(value->IsHeapNumber()); DCHECK(value->IsHeapNumber());
HeapNumber* num = HeapNumber::cast(value); HeapNumber* num = HeapNumber::cast(value);
CHECK_GE(num->value(), static_cast<double>(Smi::kMinValue)); CHECK_GE(num->value(), Smi::kMinValue);
CHECK_LE(num->value(), static_cast<double>(Smi::kMaxValue)); CHECK_LE(num->value(), Smi::kMaxValue);
return static_cast<int32_t>(num->value()); return static_cast<int32_t>(num->value());
} }
...@@ -394,9 +394,8 @@ Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName( ...@@ -394,9 +394,8 @@ Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
DCHECK_GT(module()->functions.size(), func_index); DCHECK_GT(module()->functions.size(), func_index);
WasmFunction& function = module()->functions[func_index]; WasmFunction& function = module()->functions[func_index];
SeqOneByteString* bytes = ptr_to_module_bytes(); SeqOneByteString* bytes = ptr_to_module_bytes();
DCHECK_GE(static_cast<size_t>(bytes->length()), function.name_offset); DCHECK_GE(bytes->length(), function.name_offset);
DCHECK_GE(static_cast<size_t>(bytes->length() - function.name_offset), DCHECK_GE(bytes->length() - function.name_offset, function.name_length);
function.name_length);
return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset, return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset,
function.name_length); function.name_length);
} }
...@@ -404,8 +403,7 @@ Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName( ...@@ -404,8 +403,7 @@ Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) const { int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) const {
std::vector<WasmFunction>& functions = module()->functions; std::vector<WasmFunction>& functions = module()->functions;
if (static_cast<uint32_t>(func_index) >= functions.size()) return -1; if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
DCHECK_GE(static_cast<uint32_t>(kMaxInt), DCHECK_GE(kMaxInt, functions[func_index].code_start_offset);
functions[func_index].code_start_offset);
return static_cast<int>(functions[func_index].code_start_offset); return static_cast<int>(functions[func_index].code_start_offset);
} }
...@@ -470,7 +468,7 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable( ...@@ -470,7 +468,7 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable(
} }
// Wasm bytes must be valid and must contain asm.js offset table. // Wasm bytes must be valid and must contain asm.js offset table.
DCHECK(asm_offsets.ok()); DCHECK(asm_offsets.ok());
DCHECK_GE(static_cast<size_t>(kMaxInt), asm_offsets.val.size()); DCHECK_GE(kMaxInt, asm_offsets.val.size());
int num_functions = static_cast<int>(asm_offsets.val.size()); int num_functions = static_cast<int>(asm_offsets.val.size());
int num_imported_functions = int num_imported_functions =
static_cast<int>(compiled_module->module()->num_imported_functions); static_cast<int>(compiled_module->module()->num_imported_functions);
......
...@@ -232,7 +232,7 @@ void wasm::PrintWasmText( ...@@ -232,7 +232,7 @@ void wasm::PrintWasmText(
} }
case kExprCallIndirect: { case kExprCallIndirect: {
CallIndirectOperand operand(&i, i.pc()); CallIndirectOperand operand(&i, i.pc());
DCHECK_EQ(0U, operand.table_index); DCHECK_EQ(0, operand.table_index);
os << "call_indirect " << operand.index; os << "call_indirect " << operand.index;
break; break;
} }
......
...@@ -2,24 +2,64 @@ ...@@ -2,24 +2,64 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <cstdint>
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/objects.h"
#include "testing/gtest-support.h" #include "testing/gtest-support.h"
namespace v8 { namespace v8 {
namespace base { namespace base {
namespace { namespace {
template <typename Lhs, typename Rhs>
std::string *CallCheckEQ(Lhs lhs, Rhs rhs, const char *msg) { #define CHECK_SUCCEED(NAME, lhs, rhs) \
return CheckEQImpl<Lhs, Rhs>(lhs, rhs, msg); { \
} std::string* error_message = \
Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
EXPECT_EQ(nullptr, error_message); \
}
#define CHECK_FAIL(NAME, lhs, rhs) \
{ \
std::string* error_message = \
Check##NAME##Impl<decltype(lhs), decltype(rhs)>((lhs), (rhs), ""); \
EXPECT_NE(nullptr, error_message); \
}
} // namespace } // namespace
TEST(LoggingTest, CheckEQImpl) { TEST(LoggingTest, CheckEQImpl) {
EXPECT_EQ(nullptr, CallCheckEQ(0.0, 0.0, "")); CHECK_SUCCEED(EQ, 0.0, 0.0)
EXPECT_EQ(nullptr, CallCheckEQ(0.0, -0.0, "")); CHECK_SUCCEED(EQ, 0.0, -0.0)
EXPECT_EQ(nullptr, CallCheckEQ(-0.0, 0.0, "")); CHECK_SUCCEED(EQ, -0.0, 0.0)
EXPECT_EQ(nullptr, CallCheckEQ(-0.0, -0.0, "")); CHECK_SUCCEED(EQ, -0.0, -0.0)
}
TEST(LoggingTest, CompareSignedMismatch) {
CHECK_SUCCEED(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(14))
CHECK_FAIL(EQ, static_cast<int32_t>(14), static_cast<uint32_t>(15))
CHECK_FAIL(EQ, static_cast<int32_t>(-1), static_cast<uint32_t>(-1))
CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(0))
CHECK_SUCCEED(LT, static_cast<int32_t>(-1), static_cast<uint32_t>(-1))
CHECK_SUCCEED(LE, static_cast<int32_t>(-1), static_cast<uint32_t>(0))
CHECK_SUCCEED(LE, static_cast<int32_t>(55), static_cast<uint32_t>(55))
CHECK_SUCCEED(LT, static_cast<int32_t>(55), static_cast<uint32_t>(0x7fffff00))
CHECK_SUCCEED(LE, static_cast<int32_t>(55), static_cast<uint32_t>(0x7fffff00))
CHECK_SUCCEED(GE, static_cast<uint32_t>(0x7fffff00), static_cast<int32_t>(55))
CHECK_SUCCEED(GT, static_cast<uint32_t>(0x7fffff00), static_cast<int32_t>(55))
CHECK_SUCCEED(GT, static_cast<uint32_t>(-1), static_cast<int32_t>(-1))
CHECK_SUCCEED(GE, static_cast<uint32_t>(0), static_cast<int32_t>(-1))
CHECK_SUCCEED(LT, static_cast<int8_t>(-1), static_cast<uint32_t>(0))
CHECK_SUCCEED(GT, static_cast<uint64_t>(0x7f01010101010101), 0)
CHECK_SUCCEED(LE, static_cast<int64_t>(0xff01010101010101),
static_cast<uint8_t>(13))
}
TEST(LoggingTest, CompareAgainstStaticConstPointer) {
// These used to produce link errors before http://crrev.com/2524093002.
CHECK_FAIL(EQ, v8::internal::Smi::kZero, v8::internal::Smi::FromInt(17));
CHECK_SUCCEED(GT, 0, v8::internal::Smi::kMinValue);
} }
} // namespace base } // namespace base
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment