blob: b58b073f3b7939736499e39caa4fea653634a53c [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 "test/cctest/cctest.h"
37#include "test/cctest/test-code-stubs.h"
38
39using namespace v8::internal;
40
41
42#define __ assm.
43
44ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate,
45 Register source_reg,
46 Register destination_reg) {
47 // Allocate an executable page of memory.
48 size_t actual_size;
49 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
50 Assembler::kMinimalBufferSize, &actual_size, true));
51 CHECK(buffer);
52 HandleScope handles(isolate);
53 MacroAssembler assm(isolate, buffer, static_cast<int>(actual_size));
54 int offset =
55 source_reg.is(rsp) ? 0 : (HeapNumber::kValueOffset - kSmiTagSize);
56 DoubleToIStub stub(isolate, source_reg, destination_reg, offset, true);
57 byte* start = stub.GetCode()->instruction_start();
58
59 __ pushq(rbx);
60 __ pushq(rcx);
61 __ pushq(rdx);
62 __ pushq(rsi);
63 __ pushq(rdi);
64
65 if (!source_reg.is(rsp)) {
66 // The argument we pass to the stub is not a heap number, but instead
67 // stack-allocated and offset-wise made to look like a heap number for
68 // the stub. We create that "heap number" after pushing all allocatable
69 // registers.
70 int double_argument_slot =
71 (Register::NumAllocatableRegisters() - 1) * kPointerSize + kDoubleSize;
72 __ leaq(source_reg, MemOperand(rsp, -double_argument_slot - offset));
73 }
74
75 // Save registers make sure they don't get clobbered.
76 int reg_num = 0;
77 for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) {
78 Register reg = Register::FromAllocationIndex(reg_num);
79 if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) {
80 __ pushq(reg);
81 }
82 }
83
84 // Put the double argument into the designated double argument slot.
85 __ subq(rsp, Immediate(kDoubleSize));
86 __ movsd(MemOperand(rsp, 0), xmm0);
87
88 // Call through to the actual stub
89 __ Call(start, RelocInfo::EXTERNAL_REFERENCE);
90
91 __ addq(rsp, Immediate(kDoubleSize));
92
93 // Make sure no registers have been unexpectedly clobbered
94 for (--reg_num; reg_num >= 0; --reg_num) {
95 Register reg = Register::FromAllocationIndex(reg_num);
96 if (!reg.is(rsp) && !reg.is(rbp) && !reg.is(destination_reg)) {
97 __ cmpq(reg, MemOperand(rsp, 0));
98 __ Assert(equal, kRegisterWasClobbered);
99 __ addq(rsp, Immediate(kPointerSize));
100 }
101 }
102
103 __ movq(rax, destination_reg);
104
105 __ popq(rdi);
106 __ popq(rsi);
107 __ popq(rdx);
108 __ popq(rcx);
109 __ popq(rbx);
110
111 __ ret(0);
112
113 CodeDesc desc;
114 assm.GetCode(&desc);
115 return reinterpret_cast<ConvertDToIFunc>(
116 reinterpret_cast<intptr_t>(buffer));
117}
118
119#undef __
120
121
122static Isolate* GetIsolateFrom(LocalContext* context) {
123 return reinterpret_cast<Isolate*>((*context)->GetIsolate());
124}
125
126
127TEST(ConvertDToI) {
128 CcTest::InitializeVM();
129 LocalContext context;
130 Isolate* isolate = GetIsolateFrom(&context);
131 HandleScope scope(isolate);
132
133#if DEBUG
134 // Verify that the tests actually work with the C version. In the release
135 // code, the compiler optimizes it away because it's all constant, but does it
136 // wrong, triggering an assert on gcc.
137 RunAllTruncationTests(&ConvertDToICVersion);
138#endif
139
140 Register source_registers[] = {rsp, rax, rbx, rcx, rdx, rsi, rdi, r8, r9};
141 Register dest_registers[] = {rax, rbx, rcx, rdx, rsi, rdi, r8, r9};
142
143 for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) {
144 for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) {
145 RunAllTruncationTests(
146 MakeConvertDToIFuncTrampoline(isolate,
147 source_registers[s],
148 dest_registers[d]));
149 }
150 }
151}