OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 #include <stdlib.h> |
| 29 |
| 30 #include "v8.h" |
| 31 |
| 32 #include "cctest.h" |
| 33 #include "code-stubs.h" |
| 34 #include "factory.h" |
| 35 #include "macro-assembler.h" |
| 36 #include "platform.h" |
| 37 |
| 38 #if __GNUC__ |
| 39 #define STDCALL __attribute__((stdcall)) |
| 40 #else |
| 41 #define STDCALL __stdcall |
| 42 #endif |
| 43 |
| 44 using namespace v8::internal; |
| 45 |
| 46 |
| 47 typedef int32_t STDCALL (*ConvertDToIFunc)(double input); |
| 48 |
| 49 |
| 50 int STDCALL ConvertDToICVersion(double d) { |
| 51 Address double_ptr = reinterpret_cast<Address>(&d); |
| 52 uint32_t exponent_bits = Memory::uint32_at(double_ptr + kDoubleSize / 2); |
| 53 int32_t shifted_mask = static_cast<int32_t>(Double::kExponentMask >> 32); |
| 54 int32_t exponent = (((exponent_bits & shifted_mask) >> |
| 55 (Double::kPhysicalSignificandSize - 32)) - |
| 56 HeapNumber::kExponentBias); |
| 57 uint32_t unsigned_exponent = static_cast<uint32_t>(exponent); |
| 58 int result = 0; |
| 59 uint32_t max_exponent = |
| 60 static_cast<uint32_t>(Double::kPhysicalSignificandSize); |
| 61 if (unsigned_exponent >= max_exponent) { |
| 62 if ((exponent - Double::kPhysicalSignificandSize) < 32) { |
| 63 result = Memory::uint32_at(double_ptr) << |
| 64 (exponent - Double::kPhysicalSignificandSize); |
| 65 } |
| 66 } else { |
| 67 uint64_t big_result = |
| 68 (BitCast<uint64_t>(d) & Double::kSignificandMask) | Double::kHiddenBit; |
| 69 big_result = big_result >> (Double::kPhysicalSignificandSize - exponent); |
| 70 result = static_cast<uint32_t>(big_result); |
| 71 } |
| 72 if (static_cast<int32_t>(exponent_bits) < 0) { |
| 73 return (0 - result); |
| 74 } else { |
| 75 return result; |
| 76 } |
| 77 } |
| 78 |
| 79 |
| 80 void RunOneTruncationTestWithTest(ConvertDToIFunc func, |
| 81 double from, |
| 82 int64_t to) { |
| 83 int result = (*func)(from); |
| 84 CHECK_EQ(static_cast<int>(to), result); |
| 85 } |
| 86 |
| 87 |
| 88 // #define NaN and Infinity so that it's possible to cut-and-paste these tests |
| 89 // directly to a .js file and run them. |
| 90 #define NaN NAN |
| 91 #define Infinity INFINITY |
| 92 #define RunOneTruncationTest(p1, p2) RunOneTruncationTestWithTest(func, p1, p2) |
| 93 |
| 94 void RunAllTruncationTests(ConvertDToIFunc func) { |
| 95 RunOneTruncationTest(0, 0); |
| 96 RunOneTruncationTest(0.5, 0); |
| 97 RunOneTruncationTest(-0.5, 0); |
| 98 RunOneTruncationTest(1.5, 1); |
| 99 RunOneTruncationTest(-1.5, -1); |
| 100 RunOneTruncationTest(5.5, 5); |
| 101 RunOneTruncationTest(-5.0, -5); |
| 102 RunOneTruncationTest(NaN, 0); |
| 103 RunOneTruncationTest(Infinity, 0); |
| 104 RunOneTruncationTest(-NaN, 0); |
| 105 RunOneTruncationTest(-Infinity, 0); |
| 106 |
| 107 RunOneTruncationTest(4.5036e+15, 0x1635E000); |
| 108 RunOneTruncationTest(-4.5036e+15, -372629504); |
| 109 |
| 110 RunOneTruncationTest(4503603922337791.0, -1); |
| 111 RunOneTruncationTest(-4503603922337791.0, 1); |
| 112 RunOneTruncationTest(4503601774854143.0, 2147483647); |
| 113 RunOneTruncationTest(-4503601774854143.0, -2147483647); |
| 114 RunOneTruncationTest(9007207844675582.0, -2); |
| 115 RunOneTruncationTest(-9007207844675582.0, 2); |
| 116 RunOneTruncationTest(2.4178527921507624e+24, -536870912); |
| 117 RunOneTruncationTest(-2.4178527921507624e+24, 536870912); |
| 118 RunOneTruncationTest(2.417853945072267e+24, -536870912); |
| 119 RunOneTruncationTest(-2.417853945072267e+24, 536870912); |
| 120 |
| 121 RunOneTruncationTest(4.8357055843015248e+24, -1073741824); |
| 122 RunOneTruncationTest(-4.8357055843015248e+24, 1073741824); |
| 123 RunOneTruncationTest(4.8357078901445341e+24, -1073741824); |
| 124 RunOneTruncationTest(-4.8357078901445341e+24, 1073741824); |
| 125 |
| 126 RunOneTruncationTest(9.6714111686030497e+24, -2147483648.0); |
| 127 RunOneTruncationTest(-9.6714111686030497e+24, -2147483648.0); |
| 128 RunOneTruncationTest(9.6714157802890681e+24, -2147483648.0); |
| 129 RunOneTruncationTest(-9.6714157802890681e+24, -2147483648.0); |
| 130 } |
| 131 |
| 132 #undef NaN |
| 133 #undef Infinity |
| 134 #undef RunOneTruncationTest |
| 135 |
| 136 #define __ assm. |
| 137 |
| 138 ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, |
| 139 Register source_reg, |
| 140 Register destination_reg) { |
| 141 // Allocate an executable page of memory. |
| 142 size_t actual_size; |
| 143 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
| 144 &actual_size, |
| 145 true)); |
| 146 CHECK(buffer); |
| 147 HandleScope handles(isolate); |
| 148 MacroAssembler assm(isolate, buffer, static_cast<int>(actual_size)); |
| 149 assm.set_allow_stub_calls(false); |
| 150 int offset = |
| 151 source_reg.is(esp) ? 0 : (HeapNumber::kValueOffset - kSmiTagSize); |
| 152 DoubleToIStub stub(source_reg, destination_reg, offset, true); |
| 153 byte* start = stub.GetCode(isolate)->instruction_start(); |
| 154 |
| 155 __ push(ebx); |
| 156 __ push(ecx); |
| 157 __ push(edx); |
| 158 __ push(esi); |
| 159 __ push(edi); |
| 160 |
| 161 if (!source_reg.is(esp)) { |
| 162 __ lea(source_reg, MemOperand(esp, 6 * kPointerSize - offset)); |
| 163 } |
| 164 |
| 165 int param_offset = 7 * kPointerSize; |
| 166 // Save registers make sure they don't get clobbered. |
| 167 int reg_num = 0; |
| 168 for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { |
| 169 Register reg = Register::from_code(reg_num); |
| 170 if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) { |
| 171 __ push(reg); |
| 172 param_offset += kPointerSize; |
| 173 } |
| 174 } |
| 175 |
| 176 // Re-push the double argument |
| 177 __ push(MemOperand(esp, param_offset)); |
| 178 __ push(MemOperand(esp, param_offset)); |
| 179 |
| 180 // Call through to the actual stub |
| 181 __ call(start, RelocInfo::EXTERNAL_REFERENCE); |
| 182 |
| 183 __ add(esp, Immediate(kDoubleSize)); |
| 184 |
| 185 // Make sure no registers have been unexpectedly clobbered |
| 186 for (--reg_num; reg_num >= 0; --reg_num) { |
| 187 Register reg = Register::from_code(reg_num); |
| 188 if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) { |
| 189 __ cmp(reg, MemOperand(esp, 0)); |
| 190 __ Assert(equal, "register was clobbered"); |
| 191 __ add(esp, Immediate(kPointerSize)); |
| 192 } |
| 193 } |
| 194 |
| 195 __ mov(eax, destination_reg); |
| 196 |
| 197 __ pop(edi); |
| 198 __ pop(esi); |
| 199 __ pop(edx); |
| 200 __ pop(ecx); |
| 201 __ pop(ebx); |
| 202 |
| 203 __ ret(kDoubleSize); |
| 204 |
| 205 CodeDesc desc; |
| 206 assm.GetCode(&desc); |
| 207 return reinterpret_cast<ConvertDToIFunc>( |
| 208 reinterpret_cast<intptr_t>(buffer)); |
| 209 } |
| 210 |
| 211 #undef __ |
| 212 |
| 213 |
| 214 static Isolate* GetIsolateFrom(LocalContext* context) { |
| 215 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); |
| 216 } |
| 217 |
| 218 |
| 219 TEST(ConvertDToI) { |
| 220 CcTest::InitializeVM(); |
| 221 LocalContext context; |
| 222 Isolate* isolate = GetIsolateFrom(&context); |
| 223 HandleScope scope(isolate); |
| 224 |
| 225 #if DEBUG |
| 226 // Verify that the tests actually work with the C version. In the release |
| 227 // code, the compiler optimizes it away because it's all constant, but does it |
| 228 // wrong, triggering an assert on gcc. |
| 229 RunAllTruncationTests(&ConvertDToICVersion); |
| 230 #endif |
| 231 |
| 232 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, eax)); |
| 233 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, ebx)); |
| 234 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, ecx)); |
| 235 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, edx)); |
| 236 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, edi)); |
| 237 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esp, esi)); |
| 238 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, eax)); |
| 239 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, ebx)); |
| 240 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, ecx)); |
| 241 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, edx)); |
| 242 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, edi)); |
| 243 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, eax, esi)); |
| 244 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, eax)); |
| 245 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, ebx)); |
| 246 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, ecx)); |
| 247 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, edx)); |
| 248 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, edi)); |
| 249 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ebx, esi)); |
| 250 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, eax)); |
| 251 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, ebx)); |
| 252 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, ecx)); |
| 253 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, edx)); |
| 254 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, edi)); |
| 255 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, ecx, esi)); |
| 256 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, eax)); |
| 257 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, ebx)); |
| 258 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, ecx)); |
| 259 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, edx)); |
| 260 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, edi)); |
| 261 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edx, esi)); |
| 262 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, eax)); |
| 263 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, ebx)); |
| 264 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, ecx)); |
| 265 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, edx)); |
| 266 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, edi)); |
| 267 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, esi, esi)); |
| 268 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, eax)); |
| 269 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, ebx)); |
| 270 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, ecx)); |
| 271 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, edx)); |
| 272 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, edi)); |
| 273 RunAllTruncationTests(MakeConvertDToIFuncTrampoline(isolate, edi, esi)); |
| 274 } |
OLD | NEW |