From f72a11dd4b0dd86bc4b1baa37bfa47fc8d5572b5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 30 Oct 2014 15:41:08 -0700 Subject: [PATCH] Add math routines with defined wrapping behavior for the interpreter. Add a RSUB_INT_LIT16 instruction alias to make instruction opcode switch statements easier to read. Change-Id: I3bac07c9518665abf0b05b5c3105a90be22f780a --- runtime/dex_instruction.h | 1 + runtime/interpreter/interpreter_common.h | 4 +- runtime/interpreter/interpreter_goto_table_impl.cc | 73 ++++++++++---------- runtime/interpreter/interpreter_switch_impl.cc | 78 +++++++++++----------- runtime/interpreter/safe_math.h | 65 ++++++++++++++++++ runtime/verifier/method_verifier.cc | 2 +- 6 files changed, 144 insertions(+), 79 deletions(-) create mode 100644 runtime/interpreter/safe_math.h diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h index b91322035..72802e491 100644 --- a/runtime/dex_instruction.h +++ b/runtime/dex_instruction.h @@ -88,6 +88,7 @@ class Instruction { DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) #undef DEX_INSTRUCTION_LIST #undef INSTRUCTION_ENUM + RSUB_INT_LIT16 = RSUB_INT, }; enum Format { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 6a0aaf252..7f6303ab9 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -216,7 +216,7 @@ static inline String* ResolveString(Thread* self, ShadowFrame& shadow_frame, uin static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const int32_t kMinInt = std::numeric_limits::min(); + constexpr int32_t kMinInt = std::numeric_limits::min(); if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); return false; @@ -234,7 +234,7 @@ static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg, int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const int32_t kMinInt = std::numeric_limits::min(); + constexpr int32_t kMinInt = std::numeric_limits::min(); if (UNLIKELY(divisor == 0)) { ThrowArithmeticExceptionDivideByZero(); return false; diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc index 3a177ebde..6350c56cf 100644 --- a/runtime/interpreter/interpreter_goto_table_impl.cc +++ b/runtime/interpreter/interpreter_goto_table_impl.cc @@ -15,6 +15,7 @@ */ #include "interpreter_common.h" +#include "safe_math.h" namespace art { namespace interpreter { @@ -1634,22 +1635,22 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_INT) shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) + - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(SUB_INT) shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) - - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(MUL_INT) shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) * - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); @@ -1713,22 +1714,22 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_LONG) shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) + - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(SUB_LONG) shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) - - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(MUL_LONG) shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) * - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); @@ -1863,8 +1864,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_INT_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) + - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + SafeAdd(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -1872,8 +1873,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(SUB_INT_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) - - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + SafeSub(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -1881,8 +1882,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(MUL_INT_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) * - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + SafeMul(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -1960,8 +1961,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_LONG_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) + - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeAdd(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -1969,8 +1970,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(SUB_LONG_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) - - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeSub(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -1978,8 +1979,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(MUL_LONG_2ADDR) { uint32_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) * - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeMul(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); ADVANCE(1); } HANDLE_INSTRUCTION_END(); @@ -2146,22 +2147,22 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_INT_LIT16) shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) + - inst->VRegC_22s()); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)), + inst->VRegC_22s())); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(RSUB_INT) shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - inst->VRegC_22s() - - shadow_frame.GetVReg(inst->VRegB_22s(inst_data))); + SafeSub(inst->VRegC_22s(), + shadow_frame.GetVReg(inst->VRegB_22s(inst_data)))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(MUL_INT_LIT16) shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) * - inst->VRegC_22s()); + SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)), + inst->VRegC_22s())); ADVANCE(2); HANDLE_INSTRUCTION_END(); @@ -2202,22 +2203,22 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* HANDLE_INSTRUCTION_START(ADD_INT_LIT8) shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - shadow_frame.GetVReg(inst->VRegB_22b()) + - inst->VRegC_22b()); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), + inst->VRegC_22b())); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(RSUB_INT_LIT8) shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - inst->VRegC_22b() - - shadow_frame.GetVReg(inst->VRegB_22b())); + SafeSub(inst->VRegC_22b(), + shadow_frame.GetVReg(inst->VRegB_22b()))); ADVANCE(2); HANDLE_INSTRUCTION_END(); HANDLE_INSTRUCTION_START(MUL_INT_LIT8) shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - shadow_frame.GetVReg(inst->VRegB_22b()) * - inst->VRegC_22b()); + SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), + inst->VRegC_22b())); ADVANCE(2); HANDLE_INSTRUCTION_END(); diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 9fb90f187..1b6f53e6c 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -15,6 +15,7 @@ */ #include "interpreter_common.h" +#include "safe_math.h" namespace art { namespace interpreter { @@ -1495,25 +1496,26 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem static_cast(shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; - case Instruction::ADD_INT: + case Instruction::ADD_INT: { PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) + - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; + } case Instruction::SUB_INT: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) - - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; case Instruction::MUL_INT: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_23x(inst_data), - shadow_frame.GetVReg(inst->VRegB_23x()) * - shadow_frame.GetVReg(inst->VRegC_23x())); + SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()), + shadow_frame.GetVReg(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; case Instruction::DIV_INT: { @@ -1577,29 +1579,29 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem case Instruction::ADD_LONG: PREAMBLE(); shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) + - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; case Instruction::SUB_LONG: PREAMBLE(); shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) - - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; case Instruction::MUL_LONG: PREAMBLE(); shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), - shadow_frame.GetVRegLong(inst->VRegB_23x()) * - shadow_frame.GetVRegLong(inst->VRegC_23x())); + SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()), + shadow_frame.GetVRegLong(inst->VRegC_23x()))); inst = inst->Next_2xx(); break; case Instruction::DIV_LONG: PREAMBLE(); DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_23x()), - shadow_frame.GetVRegLong(inst->VRegC_23x())); + shadow_frame.GetVRegLong(inst->VRegC_23x())); POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx); break; case Instruction::REM_LONG: @@ -1724,9 +1726,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem case Instruction::ADD_INT_2ADDR: { PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); - shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) + - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -1734,8 +1735,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) - - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + SafeSub(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -1743,8 +1744,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVReg(vregA, - shadow_frame.GetVReg(vregA) * - shadow_frame.GetVReg(inst->VRegB_12x(inst_data))); + SafeMul(shadow_frame.GetVReg(vregA), + shadow_frame.GetVReg(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -1822,8 +1823,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) + - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeAdd(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -1831,8 +1832,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) - - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeSub(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -1840,8 +1841,8 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem PREAMBLE(); uint4_t vregA = inst->VRegA_12x(inst_data); shadow_frame.SetVRegLong(vregA, - shadow_frame.GetVRegLong(vregA) * - shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))); + SafeMul(shadow_frame.GetVRegLong(vregA), + shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)))); inst = inst->Next_1xx(); break; } @@ -2008,22 +2009,22 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem case Instruction::ADD_INT_LIT16: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) + - inst->VRegC_22s()); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)), + inst->VRegC_22s())); inst = inst->Next_2xx(); break; - case Instruction::RSUB_INT: + case Instruction::RSUB_INT_LIT16: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - inst->VRegC_22s() - - shadow_frame.GetVReg(inst->VRegB_22s(inst_data))); + SafeSub(inst->VRegC_22s(), + shadow_frame.GetVReg(inst->VRegB_22s(inst_data)))); inst = inst->Next_2xx(); break; case Instruction::MUL_INT_LIT16: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22s(inst_data), - shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) * - inst->VRegC_22s()); + SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)), + inst->VRegC_22s())); inst = inst->Next_2xx(); break; case Instruction::DIV_INT_LIT16: { @@ -2064,22 +2065,19 @@ JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem case Instruction::ADD_INT_LIT8: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - shadow_frame.GetVReg(inst->VRegB_22b()) + - inst->VRegC_22b()); + SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b())); inst = inst->Next_2xx(); break; case Instruction::RSUB_INT_LIT8: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - inst->VRegC_22b() - - shadow_frame.GetVReg(inst->VRegB_22b())); + SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b()))); inst = inst->Next_2xx(); break; case Instruction::MUL_INT_LIT8: PREAMBLE(); shadow_frame.SetVReg(inst->VRegA_22b(inst_data), - shadow_frame.GetVReg(inst->VRegB_22b()) * - inst->VRegC_22b()); + SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b())); inst = inst->Next_2xx(); break; case Instruction::DIV_INT_LIT8: { diff --git a/runtime/interpreter/safe_math.h b/runtime/interpreter/safe_math.h new file mode 100644 index 000000000..78b353932 --- /dev/null +++ b/runtime/interpreter/safe_math.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_INTERPRETER_SAFE_MATH_H_ +#define ART_RUNTIME_INTERPRETER_SAFE_MATH_H_ + +#include +#include + +namespace art { +namespace interpreter { + +// Declares a type which is the larger in bit size of the two template parameters. +template +struct select_bigger { + typedef typename std::conditional= sizeof(T2), T1, T2>::type type; +}; + +// Perform signed arithmetic Op on 'a' and 'b' with defined wrapping behavior. +template