diff options
author | 2017-03-14 15:30:19 -0700 | |
---|---|---|
committer | 2017-03-16 05:31:59 -0700 | |
commit | 31afbec96e9f9c8e58778694e74aea7ce55e1378 (patch) | |
tree | 1ad1633c75fb6c65fbb25d09fb9dcf92c4a81b8c | |
parent | c53528a048e47ef8c51fc5c9667061ebd840adf1 (diff) |
ART: Bit intrinsics for Mterp interpreter
Another batch of interpreter intrinisics, mostly around bit
manipulation. Also some formatting changes and inclusion of a
comprehensive list of recognized intrinisics (to assist with
telling what's left to do).
Bug: 30933338
Benchmarks:
20% Improvement for Reversi
10% Improvement for Scimark2
3% Improvement for ChessBench
Test: ART_TEST_INTERPRETER=true m test-art-host
Test: art/tools/run-libcore-tests --host (edited for force -Xint)
Note: Added intrinsics have existing test coverage via
082-inline-execute, 123-inline-execute2, 565-checker-rotate,
564-checker-bitcount, 566-checker-signum & 567-checker-compare
Change-Id: I29f0386e28eddba37c44f9ced44e7d5f8206bb47
-rw-r--r-- | runtime/base/bit_utils.h | 113 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 292 | ||||
-rw-r--r-- | runtime/stack.h | 5 | ||||
-rw-r--r-- | runtime/utils.h | 12 |
4 files changed, 362 insertions, 60 deletions
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h index 4041f5e1ed..f536c72bae 100644 --- a/runtime/base/bit_utils.h +++ b/runtime/base/bit_utils.h @@ -27,6 +27,22 @@ namespace art { +// Like sizeof, but count how many bits a type takes. Pass type explicitly. +template <typename T> +constexpr size_t BitSizeOf() { + static_assert(std::is_integral<T>::value, "T must be integral"); + using unsigned_type = typename std::make_unsigned<T>::type; + static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!"); + static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!"); + return std::numeric_limits<unsigned_type>::digits; +} + +// Like sizeof, but count how many bits a type takes. Infers type from parameter. +template <typename T> +constexpr size_t BitSizeOf(T /*x*/) { + return BitSizeOf<T>(); +} + template<typename T> constexpr int CLZ(T x) { static_assert(std::is_integral<T>::value, "T must be integral"); @@ -37,6 +53,14 @@ constexpr int CLZ(T x) { return (sizeof(T) == sizeof(uint32_t)) ? __builtin_clz(x) : __builtin_clzll(x); } +// Similar to CLZ except that on zero input it returns bitwidth and supports signed integers. +template<typename T> +constexpr int JAVASTYLE_CLZ(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + using unsigned_type = typename std::make_unsigned<T>::type; + return (x == 0) ? BitSizeOf<T>() : CLZ(static_cast<unsigned_type>(x)); +} + template<typename T> constexpr int CTZ(T x) { static_assert(std::is_integral<T>::value, "T must be integral"); @@ -48,12 +72,32 @@ constexpr int CTZ(T x) { return (sizeof(T) == sizeof(uint32_t)) ? __builtin_ctz(x) : __builtin_ctzll(x); } +// Similar to CTZ except that on zero input it returns bitwidth and supports signed integers. +template<typename T> +constexpr int JAVASTYLE_CTZ(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + using unsigned_type = typename std::make_unsigned<T>::type; + return (x == 0) ? BitSizeOf<T>() : CTZ(static_cast<unsigned_type>(x)); +} + // Return the number of 1-bits in `x`. template<typename T> constexpr int POPCOUNT(T x) { return (sizeof(T) == sizeof(uint32_t)) ? __builtin_popcount(x) : __builtin_popcountll(x); } +// Swap bytes. +template<typename T> +constexpr T BSWAP(T x) { + if (sizeof(T) == sizeof(uint16_t)) { + return __builtin_bswap16(x); + } else if (sizeof(T) == sizeof(uint32_t)) { + return __builtin_bswap32(x); + } else { + return __builtin_bswap64(x); + } +} + // Find the bit position of the most significant bit (0-based), or -1 if there were no bits set. template <typename T> constexpr ssize_t MostSignificantBit(T value) { @@ -169,22 +213,6 @@ inline bool IsAlignedParam(T* x, int n) { #define DCHECK_ALIGNED_PARAM(value, alignment) \ DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value) -// Like sizeof, but count how many bits a type takes. Pass type explicitly. -template <typename T> -constexpr size_t BitSizeOf() { - static_assert(std::is_integral<T>::value, "T must be integral"); - using unsigned_type = typename std::make_unsigned<T>::type; - static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!"); - static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!"); - return std::numeric_limits<unsigned_type>::digits; -} - -// Like sizeof, but count how many bits a type takes. Infers type from parameter. -template <typename T> -constexpr size_t BitSizeOf(T /*x*/) { - return BitSizeOf<T>(); -} - inline uint16_t Low16Bits(uint32_t value) { return static_cast<uint16_t>(value); } @@ -363,6 +391,59 @@ IterationRange<HighToLowBitIterator<T>> HighToLowBits(T bits) { HighToLowBitIterator<T>(bits), HighToLowBitIterator<T>()); } +// Returns value with bit set in lowest one-bit position or 0 if 0. (java.lang.X.lowestOneBit). +template <typename kind> +inline static kind LowestOneBitValue(kind opnd) { + // Hacker's Delight, Section 2-1 + return opnd & -opnd; +} + +// Returns value with bit set in hightest one-bit position or 0 if 0. (java.lang.X.highestOneBit). +template <typename T> +inline static T HighestOneBitValue(T opnd) { + using unsigned_type = typename std::make_unsigned<T>::type; + T res; + if (opnd == 0) { + res = 0; + } else { + int bit_position = BitSizeOf<T>() - (CLZ(static_cast<unsigned_type>(opnd)) + 1); + res = static_cast<T>(UINT64_C(1) << bit_position); + } + return res; +} + +// Rotate bits. +template <typename T, bool left> +inline static T Rot(T opnd, int distance) { + int mask = BitSizeOf<T>() - 1; + int unsigned_right_shift = left ? (-distance & mask) : (distance & mask); + int signed_left_shift = left ? (distance & mask) : (-distance & mask); + using unsigned_type = typename std::make_unsigned<T>::type; + return (static_cast<unsigned_type>(opnd) >> unsigned_right_shift) | (opnd << signed_left_shift); +} + +// TUNING: use rbit for arm/arm64 +inline static uint32_t ReverseBits32(uint32_t opnd) { + // Hacker's Delight 7-1 + opnd = ((opnd >> 1) & 0x55555555) | ((opnd & 0x55555555) << 1); + opnd = ((opnd >> 2) & 0x33333333) | ((opnd & 0x33333333) << 2); + opnd = ((opnd >> 4) & 0x0F0F0F0F) | ((opnd & 0x0F0F0F0F) << 4); + opnd = ((opnd >> 8) & 0x00FF00FF) | ((opnd & 0x00FF00FF) << 8); + opnd = ((opnd >> 16)) | ((opnd) << 16); + return opnd; +} + +// TUNING: use rbit for arm/arm64 +inline static uint64_t ReverseBits64(uint64_t opnd) { + // Hacker's Delight 7-1 + opnd = (opnd & 0x5555555555555555L) << 1 | ((opnd >> 1) & 0x5555555555555555L); + opnd = (opnd & 0x3333333333333333L) << 2 | ((opnd >> 2) & 0x3333333333333333L); + opnd = (opnd & 0x0f0f0f0f0f0f0f0fL) << 4 | ((opnd >> 4) & 0x0f0f0f0f0f0f0f0fL); + opnd = (opnd & 0x00ff00ff00ff00ffL) << 8 | ((opnd >> 8) & 0x00ff00ff00ff00ffL); + opnd = (opnd << 48) | ((opnd & 0xffff0000L) << 16) | ((opnd >> 16) & 0xffff0000L) | (opnd >> 48); + return opnd; +} + } // namespace art #endif // ART_RUNTIME_BASE_BIT_UTILS_H_ diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc index ff0c20ec8a..0ae7307052 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -20,19 +20,29 @@ namespace art { namespace interpreter { -#define BINARY_SIMPLE_INTRINSIC(name, op, get, set, offset) \ -static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result_register) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ - inst->GetVarArgs(arg, inst_data); \ - result_register->set(op(shadow_frame->get(arg[0]), shadow_frame->get(arg[offset]))); \ - return true; \ + +#define BINARY_INTRINSIC(name, op, get1, get2, set) \ +static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ + const Instruction* inst, \ + uint16_t inst_data, \ + JValue* result_register) \ + REQUIRES_SHARED(Locks::mutator_lock_) { \ + uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ + inst->GetVarArgs(arg, inst_data); \ + result_register->set(op(shadow_frame->get1, shadow_frame->get2)); \ + return true; \ } -#define UNARY_SIMPLE_INTRINSIC(name, op, get, set) \ +#define BINARY_II_INTRINSIC(name, op, set) \ + BINARY_INTRINSIC(name, op, GetVReg(arg[0]), GetVReg(arg[1]), set) + +#define BINARY_JJ_INTRINSIC(name, op, set) \ + BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVRegLong(arg[2]), set) + +#define BINARY_JI_INTRINSIC(name, op, set) \ + BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVReg(arg[2]), set) + +#define UNARY_INTRINSIC(name, op, get, set) \ static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ const Instruction* inst, \ uint16_t inst_data, \ @@ -44,40 +54,126 @@ static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ return true; \ } + +// java.lang.Integer.reverse(I)I +UNARY_INTRINSIC(MterpIntegerReverse, ReverseBits32, GetVReg, SetI); + +// java.lang.Integer.reverseBytes(I)I +UNARY_INTRINSIC(MterpIntegerReverseBytes, BSWAP, GetVReg, SetI); + +// java.lang.Integer.bitCount(I)I +UNARY_INTRINSIC(MterpIntegerBitCount, POPCOUNT, GetVReg, SetI); + +// java.lang.Integer.compare(II)I +BINARY_II_INTRINSIC(MterpIntegerCompare, Compare, SetI); + +// java.lang.Integer.highestOneBit(I)I +UNARY_INTRINSIC(MterpIntegerHighestOneBit, HighestOneBitValue, GetVReg, SetI); + +// java.lang.Integer.LowestOneBit(I)I +UNARY_INTRINSIC(MterpIntegerLowestOneBit, LowestOneBitValue, GetVReg, SetI); + +// java.lang.Integer.numberOfLeadingZeros(I)I +UNARY_INTRINSIC(MterpIntegerNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVReg, SetI); + +// java.lang.Integer.numberOfTrailingZeros(I)I +UNARY_INTRINSIC(MterpIntegerNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVReg, SetI); + +// java.lang.Integer.rotateRight(II)I +BINARY_II_INTRINSIC(MterpIntegerRotateRight, (Rot<int32_t, false>), SetI); + +// java.lang.Integer.rotateLeft(II)I +BINARY_II_INTRINSIC(MterpIntegerRotateLeft, (Rot<int32_t, true>), SetI); + +// java.lang.Integer.signum(I)I +UNARY_INTRINSIC(MterpIntegerSignum, Signum, GetVReg, SetI); + +// java.lang.Long.reverse(I)I +UNARY_INTRINSIC(MterpLongReverse, ReverseBits64, GetVRegLong, SetJ); + +// java.lang.Long.reverseBytes(J)J +UNARY_INTRINSIC(MterpLongReverseBytes, BSWAP, GetVRegLong, SetJ); + +// java.lang.Long.bitCount(J)I +UNARY_INTRINSIC(MterpLongBitCount, POPCOUNT, GetVRegLong, SetI); + +// java.lang.Long.compare(JJ)I +BINARY_JJ_INTRINSIC(MterpLongCompare, Compare, SetI); + +// java.lang.Long.highestOneBit(J)J +UNARY_INTRINSIC(MterpLongHighestOneBit, HighestOneBitValue, GetVRegLong, SetJ); + +// java.lang.Long.lowestOneBit(J)J +UNARY_INTRINSIC(MterpLongLowestOneBit, LowestOneBitValue, GetVRegLong, SetJ); + +// java.lang.Long.numberOfLeadingZeros(J)I +UNARY_INTRINSIC(MterpLongNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVRegLong, SetJ); + +// java.lang.Long.numberOfTrailingZeros(J)I +UNARY_INTRINSIC(MterpLongNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVRegLong, SetJ); + +// java.lang.Long.rotateRight(JI)J +BINARY_JJ_INTRINSIC(MterpLongRotateRight, (Rot<int64_t, false>), SetJ); + +// java.lang.Long.rotateLeft(JI)J +BINARY_JJ_INTRINSIC(MterpLongRotateLeft, (Rot<int64_t, true>), SetJ); + +// java.lang.Long.signum(J)I +UNARY_INTRINSIC(MterpLongSignum, Signum, GetVRegLong, SetI); + +// java.lang.Short.reverseBytes(S)S +UNARY_INTRINSIC(MterpShortReverseBytes, BSWAP, GetVRegShort, SetS); + // java.lang.Math.min(II)I -BINARY_SIMPLE_INTRINSIC(MterpMathMinIntInt, std::min, GetVReg, SetI, 1); +BINARY_II_INTRINSIC(MterpMathMinIntInt, std::min, SetI); + // java.lang.Math.min(JJ)J -BINARY_SIMPLE_INTRINSIC(MterpMathMinLongLong, std::min, GetVRegLong, SetJ, 2); +BINARY_JJ_INTRINSIC(MterpMathMinLongLong, std::min, SetJ); + // java.lang.Math.max(II)I -BINARY_SIMPLE_INTRINSIC(MterpMathMaxIntInt, std::max, GetVReg, SetI, 1); +BINARY_II_INTRINSIC(MterpMathMaxIntInt, std::max, SetI); + // java.lang.Math.max(JJ)J -BINARY_SIMPLE_INTRINSIC(MterpMathMaxLongLong, std::max, GetVRegLong, SetJ, 2); +BINARY_JJ_INTRINSIC(MterpMathMaxLongLong, std::max, SetJ); + // java.lang.Math.abs(I)I -UNARY_SIMPLE_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI); +UNARY_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI); + // java.lang.Math.abs(J)J -UNARY_SIMPLE_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ); +UNARY_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ); + // java.lang.Math.abs(F)F -UNARY_SIMPLE_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI); +UNARY_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI); + // java.lang.Math.abs(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ); +UNARY_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ); + // java.lang.Math.sqrt(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD); + // java.lang.Math.ceil(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD); + // java.lang.Math.floor(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD); + // java.lang.Math.sin(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD); + // java.lang.Math.cos(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD); + // java.lang.Math.tan(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD); + // java.lang.Math.asin(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD); + // java.lang.Math.acos(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD); + // java.lang.Math.atan(D)D -UNARY_SIMPLE_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD); +UNARY_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD); // java.lang.String.charAt(I)C static ALWAYS_INLINE bool MterpStringCharAt(ShadowFrame* shadow_frame, @@ -224,6 +320,12 @@ static ALWAYS_INLINE bool MterpStringEquals(ShadowFrame* shadow_frame, return true; } +// Macro to help keep track of what's left to implement. +#define UNIMPLEMENTED_CASE(name) \ + case Intrinsics::k##name: \ + res = false; \ + break; + #define INTRINSIC_CASE(name) \ case Intrinsics::k##name: \ res = Mterp##name(shadow_frame, inst, inst_data, result_register); \ @@ -238,34 +340,136 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, Intrinsics intrinsic = static_cast<Intrinsics>(called_method->GetIntrinsic()); bool res = false; // Assume failure switch (intrinsic) { - INTRINSIC_CASE(MathMinIntInt) + UNIMPLEMENTED_CASE(DoubleDoubleToRawLongBits /* (D)J */) + UNIMPLEMENTED_CASE(DoubleDoubleToLongBits /* (D)J */) + UNIMPLEMENTED_CASE(DoubleIsInfinite /* (D)Z */) + UNIMPLEMENTED_CASE(DoubleIsNaN /* (D)Z */) + UNIMPLEMENTED_CASE(DoubleLongBitsToDouble /* (J)D */) + UNIMPLEMENTED_CASE(FloatFloatToRawIntBits /* (F)I */) + UNIMPLEMENTED_CASE(FloatFloatToIntBits /* (F)I */) + UNIMPLEMENTED_CASE(FloatIsInfinite /* (F)Z */) + UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */) + UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */) + INTRINSIC_CASE(IntegerReverse) + INTRINSIC_CASE(IntegerReverseBytes) + INTRINSIC_CASE(IntegerBitCount) + INTRINSIC_CASE(IntegerCompare) + INTRINSIC_CASE(IntegerHighestOneBit) + INTRINSIC_CASE(IntegerLowestOneBit) + INTRINSIC_CASE(IntegerNumberOfLeadingZeros) + INTRINSIC_CASE(IntegerNumberOfTrailingZeros) + INTRINSIC_CASE(IntegerRotateRight) + INTRINSIC_CASE(IntegerRotateLeft) + INTRINSIC_CASE(IntegerSignum) + INTRINSIC_CASE(LongReverse) + INTRINSIC_CASE(LongReverseBytes) + INTRINSIC_CASE(LongBitCount) + INTRINSIC_CASE(LongCompare) + INTRINSIC_CASE(LongHighestOneBit) + INTRINSIC_CASE(LongLowestOneBit) + INTRINSIC_CASE(LongNumberOfLeadingZeros) + INTRINSIC_CASE(LongNumberOfTrailingZeros) + INTRINSIC_CASE(LongRotateRight) + INTRINSIC_CASE(LongRotateLeft) + INTRINSIC_CASE(LongSignum) + INTRINSIC_CASE(ShortReverseBytes) + INTRINSIC_CASE(MathAbsDouble) + INTRINSIC_CASE(MathAbsFloat) + INTRINSIC_CASE(MathAbsLong) + INTRINSIC_CASE(MathAbsInt) + UNIMPLEMENTED_CASE(MathMinDoubleDouble /* (DD)D */) + UNIMPLEMENTED_CASE(MathMinFloatFloat /* (FF)F */) INTRINSIC_CASE(MathMinLongLong) - INTRINSIC_CASE(MathMaxIntInt) + INTRINSIC_CASE(MathMinIntInt) + UNIMPLEMENTED_CASE(MathMaxDoubleDouble /* (DD)D */) + UNIMPLEMENTED_CASE(MathMaxFloatFloat /* (FF)F */) INTRINSIC_CASE(MathMaxLongLong) - INTRINSIC_CASE(MathAbsInt) - INTRINSIC_CASE(MathAbsLong) - INTRINSIC_CASE(MathAbsFloat) - INTRINSIC_CASE(MathAbsDouble) - INTRINSIC_CASE(MathSqrt) - INTRINSIC_CASE(MathCeil) - INTRINSIC_CASE(MathFloor) - INTRINSIC_CASE(MathSin) + INTRINSIC_CASE(MathMaxIntInt) INTRINSIC_CASE(MathCos) - INTRINSIC_CASE(MathTan) - INTRINSIC_CASE(MathAsin) + INTRINSIC_CASE(MathSin) INTRINSIC_CASE(MathAcos) + INTRINSIC_CASE(MathAsin) INTRINSIC_CASE(MathAtan) + UNIMPLEMENTED_CASE(MathAtan2 /* (DD)D */) + UNIMPLEMENTED_CASE(MathCbrt /* (D)D */) + UNIMPLEMENTED_CASE(MathCosh /* (D)D */) + UNIMPLEMENTED_CASE(MathExp /* (D)D */) + UNIMPLEMENTED_CASE(MathExpm1 /* (D)D */) + UNIMPLEMENTED_CASE(MathHypot /* (DD)D */) + UNIMPLEMENTED_CASE(MathLog /* (D)D */) + UNIMPLEMENTED_CASE(MathLog10 /* (D)D */) + UNIMPLEMENTED_CASE(MathNextAfter /* (DD)D */) + UNIMPLEMENTED_CASE(MathSinh /* (D)D */) + INTRINSIC_CASE(MathTan) + UNIMPLEMENTED_CASE(MathTanh /* (D)D */) + INTRINSIC_CASE(MathSqrt) + INTRINSIC_CASE(MathCeil) + INTRINSIC_CASE(MathFloor) + UNIMPLEMENTED_CASE(MathRint /* (D)D */) + UNIMPLEMENTED_CASE(MathRoundDouble /* (D)J */) + UNIMPLEMENTED_CASE(MathRoundFloat /* (F)I */) + UNIMPLEMENTED_CASE(SystemArrayCopyChar /* ([CI[CII)V */) + UNIMPLEMENTED_CASE(SystemArrayCopy /* (Ljava/lang/Object;ILjava/lang/Object;II)V */) + UNIMPLEMENTED_CASE(ThreadCurrentThread /* ()Ljava/lang/Thread; */) + UNIMPLEMENTED_CASE(MemoryPeekByte /* (J)B */) + UNIMPLEMENTED_CASE(MemoryPeekIntNative /* (J)I */) + UNIMPLEMENTED_CASE(MemoryPeekLongNative /* (J)J */) + UNIMPLEMENTED_CASE(MemoryPeekShortNative /* (J)S */) + UNIMPLEMENTED_CASE(MemoryPokeByte /* (JB)V */) + UNIMPLEMENTED_CASE(MemoryPokeIntNative /* (JI)V */) + UNIMPLEMENTED_CASE(MemoryPokeLongNative /* (JJ)V */) + UNIMPLEMENTED_CASE(MemoryPokeShortNative /* (JS)V */) INTRINSIC_CASE(StringCharAt) INTRINSIC_CASE(StringCompareTo) - INTRINSIC_CASE(StringIndexOf) - INTRINSIC_CASE(StringIndexOfAfter) INTRINSIC_CASE(StringEquals) INTRINSIC_CASE(StringGetCharsNoCheck) + INTRINSIC_CASE(StringIndexOf) + INTRINSIC_CASE(StringIndexOfAfter) + UNIMPLEMENTED_CASE(StringStringIndexOf /* (Ljava/lang/String;)I */) + UNIMPLEMENTED_CASE(StringStringIndexOfAfter /* (Ljava/lang/String;I)I */) INTRINSIC_CASE(StringIsEmpty) INTRINSIC_CASE(StringLength) - default: - res = false; // Punt + UNIMPLEMENTED_CASE(StringNewStringFromBytes /* ([BIII)Ljava/lang/String; */) + UNIMPLEMENTED_CASE(StringNewStringFromChars /* (II[C)Ljava/lang/String; */) + UNIMPLEMENTED_CASE(StringNewStringFromString /* (Ljava/lang/String;)Ljava/lang/String; */) + UNIMPLEMENTED_CASE(StringBufferAppend /* (Ljava/lang/String;)Ljava/lang/StringBuffer; */) + UNIMPLEMENTED_CASE(StringBufferLength /* ()I */) + UNIMPLEMENTED_CASE(StringBufferToString /* ()Ljava/lang/String; */) + UNIMPLEMENTED_CASE(StringBuilderAppend /* (Ljava/lang/String;)Ljava/lang/StringBuilder; */) + UNIMPLEMENTED_CASE(StringBuilderLength /* ()I */) + UNIMPLEMENTED_CASE(StringBuilderToString /* ()Ljava/lang/String; */) + UNIMPLEMENTED_CASE(UnsafeCASInt /* (Ljava/lang/Object;JII)Z */) + UNIMPLEMENTED_CASE(UnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */) + UNIMPLEMENTED_CASE(UnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */) + UNIMPLEMENTED_CASE(UnsafeGet /* (Ljava/lang/Object;J)I */) + UNIMPLEMENTED_CASE(UnsafeGetVolatile /* (Ljava/lang/Object;J)I */) + UNIMPLEMENTED_CASE(UnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */) + UNIMPLEMENTED_CASE(UnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */) + UNIMPLEMENTED_CASE(UnsafeGetLong /* (Ljava/lang/Object;J)J */) + UNIMPLEMENTED_CASE(UnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */) + UNIMPLEMENTED_CASE(UnsafePut /* (Ljava/lang/Object;JI)V */) + UNIMPLEMENTED_CASE(UnsafePutOrdered /* (Ljava/lang/Object;JI)V */) + UNIMPLEMENTED_CASE(UnsafePutVolatile /* (Ljava/lang/Object;JI)V */) + UNIMPLEMENTED_CASE(UnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */) + UNIMPLEMENTED_CASE(UnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */) + UNIMPLEMENTED_CASE(UnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */) + UNIMPLEMENTED_CASE(UnsafePutLong /* (Ljava/lang/Object;JJ)V */) + UNIMPLEMENTED_CASE(UnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */) + UNIMPLEMENTED_CASE(UnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */) + UNIMPLEMENTED_CASE(UnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */) + UNIMPLEMENTED_CASE(UnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */) + UNIMPLEMENTED_CASE(UnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */) + UNIMPLEMENTED_CASE(UnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */) + UNIMPLEMENTED_CASE(UnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */) + UNIMPLEMENTED_CASE(UnsafeLoadFence /* ()V */) + UNIMPLEMENTED_CASE(UnsafeStoreFence /* ()V */) + UNIMPLEMENTED_CASE(UnsafeFullFence /* ()V */) + UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */) + UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */) + case Intrinsics::kNone: + res = false; break; + // Note: no default case to ensure we catch any newly added intrinsics. } return res; } diff --git a/runtime/stack.h b/runtime/stack.h index 90a0aee353..5c9614aba4 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -197,6 +197,11 @@ class ShadowFrame { return *reinterpret_cast<const int32_t*>(vreg); } + // Shorts are extended to Ints in VRegs. Interpreter intrinsics needs them as shorts. + int16_t GetVRegShort(size_t i) const { + return static_cast<int16_t>(GetVReg(i)); + } + uint32_t* GetVRegAddr(size_t i) { return &vregs_[i]; } diff --git a/runtime/utils.h b/runtime/utils.h index 96e5bfa8ec..24fd2053f5 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -325,6 +325,18 @@ constexpr size_t ArrayCount(const T (&)[size]) { return size; } +// Return -1 if <, 0 if ==, 1 if >. +template <typename T> +inline static int32_t Compare(T lhs, T rhs) { + return (lhs < rhs) ? -1 : ((lhs == rhs) ? 0 : 1); +} + +// Return -1 if < 0, 0 if == 0, 1 if > 0. +template <typename T> +inline static int32_t Signum(T opnd) { + return (opnd < 0) ? -1 : ((opnd == 0) ? 0 : 1); +} + } // namespace art #endif // ART_RUNTIME_UTILS_H_ |