1// Copyright 2009 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 "macro-assembler.h"
33#include "factory.h"
34#include "platform.h"
35#include "serialize.h"
36#include "cctest.h"
37
38using v8::internal::byte;
39using v8::internal::OS;
40using v8::internal::Assembler;
41using v8::internal::Operand;
42using v8::internal::Immediate;
43using v8::internal::Label;
44using v8::internal::rax;
45using v8::internal::rsi;
46using v8::internal::rdi;
47using v8::internal::rcx;
48using v8::internal::rdx;
49using v8::internal::rbp;
50using v8::internal::rsp;
51using v8::internal::FUNCTION_CAST;
52using v8::internal::CodeDesc;
53using v8::internal::less_equal;
54using v8::internal::not_equal;
55using v8::internal::greater;
56
57// Test the x64 assembler by compiling some simple functions into
58// a buffer and executing them.  These tests do not initialize the
59// V8 library, create a context, or use any V8 objects.
60// The AMD64 calling convention is used, with the first six arguments
61// in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
62// the XMM registers.  The return value is in RAX.
63// This calling convention is used on Linux, with GCC, and on Mac OS,
64// with GCC.  A different convention is used on 64-bit windows,
65// where the first four integer arguments are passed in RCX, RDX, R8 and R9.
66
67typedef int (*F0)();
68typedef int (*F1)(int64_t x);
69typedef int (*F2)(int64_t x, int64_t y);
70
71#ifdef _WIN64
72static const v8::internal::Register arg1 = rcx;
73static const v8::internal::Register arg2 = rdx;
74#else
75static const v8::internal::Register arg1 = rdi;
76static const v8::internal::Register arg2 = rsi;
77#endif
78
79#define __ assm.
80
81
82TEST(AssemblerX64ReturnOperation) {
83  // Allocate an executable page of memory.
84  size_t actual_size;
85  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
86                                                 &actual_size,
87                                                 true));
88  CHECK(buffer);
89  Assembler assm(buffer, static_cast<int>(actual_size));
90
91  // Assemble a simple function that copies argument 2 and returns it.
92  __ movq(rax, arg2);
93  __ nop();
94  __ ret(0);
95
96  CodeDesc desc;
97  assm.GetCode(&desc);
98  // Call the function from C++.
99  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
100  CHECK_EQ(2, result);
101}
102
103TEST(AssemblerX64StackOperations) {
104  // Allocate an executable page of memory.
105  size_t actual_size;
106  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
107                                                 &actual_size,
108                                                 true));
109  CHECK(buffer);
110  Assembler assm(buffer, static_cast<int>(actual_size));
111
112  // Assemble a simple function that copies argument 2 and returns it.
113  // We compile without stack frame pointers, so the gdb debugger shows
114  // incorrect stack frames when debugging this function (which has them).
115  __ push(rbp);
116  __ movq(rbp, rsp);
117  __ push(arg2);  // Value at (rbp - 8)
118  __ push(arg2);  // Value at (rbp - 16)
119  __ push(arg1);  // Value at (rbp - 24)
120  __ pop(rax);
121  __ pop(rax);
122  __ pop(rax);
123  __ pop(rbp);
124  __ nop();
125  __ ret(0);
126
127  CodeDesc desc;
128  assm.GetCode(&desc);
129  // Call the function from C++.
130  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
131  CHECK_EQ(2, result);
132}
133
134TEST(AssemblerX64ArithmeticOperations) {
135  // Allocate an executable page of memory.
136  size_t actual_size;
137  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
138                                                 &actual_size,
139                                                 true));
140  CHECK(buffer);
141  Assembler assm(buffer, static_cast<int>(actual_size));
142
143  // Assemble a simple function that adds arguments returning the sum.
144  __ movq(rax, arg2);
145  __ addq(rax, arg1);
146  __ ret(0);
147
148  CodeDesc desc;
149  assm.GetCode(&desc);
150  // Call the function from C++.
151  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
152  CHECK_EQ(5, result);
153}
154
155TEST(AssemblerX64ImulOperation) {
156  // Allocate an executable page of memory.
157  size_t actual_size;
158  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
159                                                 &actual_size,
160                                                 true));
161  CHECK(buffer);
162  Assembler assm(buffer, static_cast<int>(actual_size));
163
164  // Assemble a simple function that multiplies arguments returning the high
165  // word.
166  __ movq(rax, arg2);
167  __ imul(arg1);
168  __ movq(rax, rdx);
169  __ ret(0);
170
171  CodeDesc desc;
172  assm.GetCode(&desc);
173  // Call the function from C++.
174  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
175  CHECK_EQ(0, result);
176  result =  FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l);
177  CHECK_EQ(1, result);
178  result =  FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l);
179  CHECK_EQ(-1, result);
180}
181
182TEST(AssemblerX64MemoryOperands) {
183  // Allocate an executable page of memory.
184  size_t actual_size;
185  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
186                                                 &actual_size,
187                                                 true));
188  CHECK(buffer);
189  Assembler assm(buffer, static_cast<int>(actual_size));
190
191  // Assemble a simple function that copies argument 2 and returns it.
192  __ push(rbp);
193  __ movq(rbp, rsp);
194
195  __ push(arg2);  // Value at (rbp - 8)
196  __ push(arg2);  // Value at (rbp - 16)
197  __ push(arg1);  // Value at (rbp - 24)
198
199  const int kStackElementSize = 8;
200  __ movq(rax, Operand(rbp, -3 * kStackElementSize));
201  __ pop(arg2);
202  __ pop(arg2);
203  __ pop(arg2);
204  __ pop(rbp);
205  __ nop();
206  __ ret(0);
207
208  CodeDesc desc;
209  assm.GetCode(&desc);
210  // Call the function from C++.
211  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
212  CHECK_EQ(3, result);
213}
214
215TEST(AssemblerX64ControlFlow) {
216  // Allocate an executable page of memory.
217  size_t actual_size;
218  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
219                                                 &actual_size,
220                                                 true));
221  CHECK(buffer);
222  Assembler assm(buffer, static_cast<int>(actual_size));
223
224  // Assemble a simple function that copies argument 1 and returns it.
225  __ push(rbp);
226
227  __ movq(rbp, rsp);
228  __ movq(rax, arg1);
229  Label target;
230  __ jmp(&target);
231  __ movq(rax, arg2);
232  __ bind(&target);
233  __ pop(rbp);
234  __ ret(0);
235
236  CodeDesc desc;
237  assm.GetCode(&desc);
238  // Call the function from C++.
239  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
240  CHECK_EQ(3, result);
241}
242
243TEST(AssemblerX64LoopImmediates) {
244  // Allocate an executable page of memory.
245  size_t actual_size;
246  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
247                                                 &actual_size,
248                                                 true));
249  CHECK(buffer);
250  Assembler assm(buffer, static_cast<int>(actual_size));
251  // Assemble two loops using rax as counter, and verify the ending counts.
252  Label Fail;
253  __ movq(rax, Immediate(-3));
254  Label Loop1_test;
255  Label Loop1_body;
256  __ jmp(&Loop1_test);
257  __ bind(&Loop1_body);
258  __ addq(rax, Immediate(7));
259  __ bind(&Loop1_test);
260  __ cmpq(rax, Immediate(20));
261  __ j(less_equal, &Loop1_body);
262  // Did the loop terminate with the expected value?
263  __ cmpq(rax, Immediate(25));
264  __ j(not_equal, &Fail);
265
266  Label Loop2_test;
267  Label Loop2_body;
268  __ movq(rax, Immediate(0x11FEED00));
269  __ jmp(&Loop2_test);
270  __ bind(&Loop2_body);
271  __ addq(rax, Immediate(-0x1100));
272  __ bind(&Loop2_test);
273  __ cmpq(rax, Immediate(0x11FE8000));
274  __ j(greater, &Loop2_body);
275  // Did the loop terminate with the expected value?
276  __ cmpq(rax, Immediate(0x11FE7600));
277  __ j(not_equal, &Fail);
278
279  __ movq(rax, Immediate(1));
280  __ ret(0);
281  __ bind(&Fail);
282  __ movq(rax, Immediate(0));
283  __ ret(0);
284
285  CodeDesc desc;
286  assm.GetCode(&desc);
287  // Call the function from C++.
288  int result =  FUNCTION_CAST<F0>(buffer)();
289  CHECK_EQ(1, result);
290}
291
292#undef __
293