1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Rrdistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Rrdistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Rrdistributions 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 "src/v8.h" 31 32 #include "src/base/platform/platform.h" 33 #include "src/code-stubs.h" 34 #include "src/factory.h" 35 #include "src/macro-assembler.h" 36 #include "src/simulator.h" 37 #include "test/cctest/cctest.h" 38 #include "test/cctest/test-code-stubs.h" 39 40 using namespace v8::internal; 41 42 #define __ masm. 43 44 ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, 45 Register source_reg, 46 Register destination_reg, 47 bool inline_fastpath) { 48 // Allocate an executable page of memory. 49 size_t actual_size = 4 * Assembler::kMinimalBufferSize; 50 byte* buffer = static_cast<byte*>( 51 v8::base::OS::Allocate(actual_size, &actual_size, true)); 52 CHECK(buffer); 53 HandleScope handles(isolate); 54 MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size), 55 v8::internal::CodeObjectRequired::kYes); 56 DoubleToIStub stub(isolate, source_reg, destination_reg, 0, true, 57 inline_fastpath); 58 59 byte* start = stub.GetCode()->instruction_start(); 60 Label done; 61 62 __ SetStackPointer(csp); 63 __ PushCalleeSavedRegisters(); 64 __ Mov(jssp, csp); 65 __ SetStackPointer(jssp); 66 67 // Push the double argument. 68 __ Push(d0); 69 __ Mov(source_reg, jssp); 70 71 MacroAssembler::PushPopQueue queue(&masm); 72 73 // Save registers make sure they don't get clobbered. 74 int source_reg_offset = kDoubleSize; 75 int reg_num = 0; 76 for (; reg_num < Register::kNumRegisters; ++reg_num) { 77 Register reg = Register::from_code(reg_num); 78 if (reg.IsAllocatable()) { 79 if (!reg.is(destination_reg)) { 80 queue.Queue(reg); 81 source_reg_offset += kPointerSize; 82 } 83 } 84 } 85 // Re-push the double argument. 86 queue.Queue(d0); 87 88 queue.PushQueued(); 89 90 // Call through to the actual stub 91 if (inline_fastpath) { 92 __ Ldr(d0, MemOperand(source_reg)); 93 __ TryConvertDoubleToInt64(destination_reg, d0, &done); 94 if (destination_reg.is(source_reg)) { 95 // Restore clobbered source_reg. 96 __ add(source_reg, jssp, Operand(source_reg_offset)); 97 } 98 } 99 __ Call(start, RelocInfo::EXTERNAL_REFERENCE); 100 __ bind(&done); 101 102 __ Drop(1, kDoubleSize); 103 104 // // Make sure no registers have been unexpectedly clobbered 105 for (--reg_num; reg_num >= 0; --reg_num) { 106 Register reg = Register::from_code(reg_num); 107 if (reg.IsAllocatable()) { 108 if (!reg.is(destination_reg)) { 109 __ Pop(ip0); 110 __ cmp(reg, ip0); 111 __ Assert(eq, kRegisterWasClobbered); 112 } 113 } 114 } 115 116 __ Drop(1, kDoubleSize); 117 118 if (!destination_reg.is(x0)) 119 __ Mov(x0, destination_reg); 120 121 // Restore callee save registers. 122 __ Mov(csp, jssp); 123 __ SetStackPointer(csp); 124 __ PopCalleeSavedRegisters(); 125 126 __ Ret(); 127 128 CodeDesc desc; 129 masm.GetCode(&desc); 130 Assembler::FlushICache(isolate, buffer, actual_size); 131 return (reinterpret_cast<ConvertDToIFunc>( 132 reinterpret_cast<intptr_t>(buffer))); 133 } 134 135 #undef __ 136 137 138 static Isolate* GetIsolateFrom(LocalContext* context) { 139 return reinterpret_cast<Isolate*>((*context)->GetIsolate()); 140 } 141 142 143 int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func, 144 double from) { 145 #ifdef USE_SIMULATOR 146 Simulator::CallArgument args[] = { 147 Simulator::CallArgument(from), 148 Simulator::CallArgument::End() 149 }; 150 return static_cast<int32_t>(Simulator::current(CcTest::i_isolate()) 151 ->CallInt64(FUNCTION_ADDR(func), args)); 152 #else 153 return (*func)(from); 154 #endif 155 } 156 157 158 TEST(ConvertDToI) { 159 CcTest::InitializeVM(); 160 LocalContext context; 161 Isolate* isolate = GetIsolateFrom(&context); 162 HandleScope scope(isolate); 163 164 #if DEBUG 165 // Verify that the tests actually work with the C version. In the release 166 // code, the compiler optimizes it away because it's all constant, but does it 167 // wrong, triggering an assert on gcc. 168 RunAllTruncationTests(&ConvertDToICVersion); 169 #endif 170 171 Register source_registers[] = {jssp, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, 172 x10, x11, x12, x13, x14, x15, x18, x19, x20, 173 x21, x22, x23, x24}; 174 Register dest_registers[] = {x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, 175 x12, x13, x14, x15, x18, x19, x20, x21, x22, x23, 176 x24}; 177 178 for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) { 179 for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) { 180 RunAllTruncationTests( 181 RunGeneratedCodeCallWrapper, 182 MakeConvertDToIFuncTrampoline(isolate, 183 source_registers[s], 184 dest_registers[d], 185 false)); 186 RunAllTruncationTests( 187 RunGeneratedCodeCallWrapper, 188 MakeConvertDToIFuncTrampoline(isolate, 189 source_registers[s], 190 dest_registers[d], 191 true)); 192 } 193 } 194 } 195