ART: Simplify unstarted-runtime ceil and floor
Just use the C functions like libcore does. Add tests.
Bug: 28132336
Change-Id: Ic5f469e8504c9f2b7756280558fd1610ed8015ba
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 80ffedc..02e05c5 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -524,31 +524,14 @@
}
}
-static double ComputeCeil(double in) {
- double out;
- // Special cases:
- // 1) NaN, infinity, +0, -0 -> out := in. All are guaranteed by cmath.
- // -1 < in < 0 -> out := -0.
- if (-1.0 < in && in < 0) {
- out = -0.0;
- } else {
- out = ceil(in);
- }
- return out;
-}
-
void UnstartedRuntime::UnstartedMathCeil(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- double in = shadow_frame->GetVRegDouble(arg_offset);
- result->SetD(ComputeCeil(in));
+ result->SetD(ceil(shadow_frame->GetVRegDouble(arg_offset)));
}
void UnstartedRuntime::UnstartedMathFloor(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- double in = shadow_frame->GetVRegDouble(arg_offset);
- // From the JavaDocs:
- // "Note that the value of Math.ceil(x) is exactly the value of -Math.floor(-x)."
- result->SetD(-ComputeCeil(-in));
+ result->SetD(floor(shadow_frame->GetVRegDouble(arg_offset)));
}
void UnstartedRuntime::UnstartedObjectHashCode(
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index f40e4e3..1b5b665 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -16,6 +16,9 @@
#include "unstarted_runtime.h"
+#include <limits>
+
+#include "base/casts.h"
#include "class_linker.h"
#include "common_runtime_test.h"
#include "dex_instruction.h"
@@ -154,6 +157,31 @@
length);
CheckObjectArray(dst_handle.Get(), expected_result);
}
+
+ void TestCeilFloor(bool ceil,
+ Thread* self,
+ ShadowFrame* tmp,
+ double const test_pairs[][2],
+ size_t num_pairs)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ for (size_t i = 0; i < num_pairs; ++i) {
+ tmp->SetVRegDouble(0, test_pairs[i][0]);
+
+ JValue result;
+ if (ceil) {
+ UnstartedMathCeil(self, tmp, &result, 0);
+ } else {
+ UnstartedMathFloor(self, tmp, &result, 0);
+ }
+
+ ASSERT_FALSE(self->IsExceptionPending());
+
+ // We want precise results.
+ int64_t result_int64t = bit_cast<int64_t, double>(result.GetD());
+ int64_t expect_int64t = bit_cast<int64_t, double>(test_pairs[i][1]);
+ EXPECT_EQ(expect_int64t, result_int64t) << result.GetD() << " vs " << test_pairs[i][1];
+ }
+ }
};
TEST_F(UnstartedRuntimeTest, MemoryPeekByte) {
@@ -603,5 +631,63 @@
ShadowFrame::DeleteDeoptimizedFrame(tmp);
}
+TEST_F(UnstartedRuntimeTest, Ceil) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ constexpr double nan = std::numeric_limits<double>::quiet_NaN();
+ constexpr double inf = std::numeric_limits<double>::infinity();
+ constexpr double ld1 = static_cast<double>((UINT64_C(1) << 53) - 1);
+ constexpr double ld2 = static_cast<double>(UINT64_C(1) << 55);
+ constexpr double test_pairs[][2] = {
+ { -0.0, -0.0 },
+ { 0.0, 0.0 },
+ { -0.5, -0.0 },
+ { -1.0, -1.0 },
+ { 0.5, 1.0 },
+ { 1.0, 1.0 },
+ { nan, nan },
+ { inf, inf },
+ { -inf, -inf },
+ { ld1, ld1 },
+ { ld2, ld2 }
+ };
+
+ TestCeilFloor(true /* ceil */, self, tmp, test_pairs, arraysize(test_pairs));
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, Floor) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ constexpr double nan = std::numeric_limits<double>::quiet_NaN();
+ constexpr double inf = std::numeric_limits<double>::infinity();
+ constexpr double ld1 = static_cast<double>((UINT64_C(1) << 53) - 1);
+ constexpr double ld2 = static_cast<double>(UINT64_C(1) << 55);
+ constexpr double test_pairs[][2] = {
+ { -0.0, -0.0 },
+ { 0.0, 0.0 },
+ { -0.5, -1.0 },
+ { -1.0, -1.0 },
+ { 0.5, 0.0 },
+ { 1.0, 1.0 },
+ { nan, nan },
+ { inf, inf },
+ { -inf, -inf },
+ { ld1, ld1 },
+ { ld2, ld2 }
+ };
+
+ TestCeilFloor(false /* floor */, self, tmp, test_pairs, arraysize(test_pairs));
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
} // namespace interpreter
} // namespace art