OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 17 matching lines...) Expand all Loading... |
28 #include <stdlib.h> | 28 #include <stdlib.h> |
29 | 29 |
30 #include "v8.h" | 30 #include "v8.h" |
31 | 31 |
32 #include "macro-assembler.h" | 32 #include "macro-assembler.h" |
33 #include "factory.h" | 33 #include "factory.h" |
34 #include "platform.h" | 34 #include "platform.h" |
35 #include "serialize.h" | 35 #include "serialize.h" |
36 #include "cctest.h" | 36 #include "cctest.h" |
37 | 37 |
38 using v8::internal::Assembler; | 38 using namespace v8::internal; |
39 using v8::internal::Code; | |
40 using v8::internal::CodeDesc; | |
41 using v8::internal::FUNCTION_CAST; | |
42 using v8::internal::Immediate; | |
43 using v8::internal::Isolate; | |
44 using v8::internal::Label; | |
45 using v8::internal::OS; | |
46 using v8::internal::Operand; | |
47 using v8::internal::byte; | |
48 using v8::internal::greater; | |
49 using v8::internal::less_equal; | |
50 using v8::internal::equal; | |
51 using v8::internal::not_equal; | |
52 using v8::internal::r13; | |
53 using v8::internal::r15; | |
54 using v8::internal::r8; | |
55 using v8::internal::r9; | |
56 using v8::internal::rax; | |
57 using v8::internal::rbx; | |
58 using v8::internal::rbp; | |
59 using v8::internal::rcx; | |
60 using v8::internal::rdi; | |
61 using v8::internal::rdx; | |
62 using v8::internal::rsi; | |
63 using v8::internal::rsp; | |
64 using v8::internal::times_1; | |
65 using v8::internal::xmm0; | |
66 | 39 |
67 // Test the x64 assembler by compiling some simple functions into | 40 // Test the x64 assembler by compiling some simple functions into |
68 // a buffer and executing them. These tests do not initialize the | 41 // a buffer and executing them. These tests do not initialize the |
69 // V8 library, create a context, or use any V8 objects. | 42 // V8 library, create a context, or use any V8 objects. |
70 // The AMD64 calling convention is used, with the first six arguments | 43 // The AMD64 calling convention is used, with the first six arguments |
71 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in | 44 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in |
72 // the XMM registers. The return value is in RAX. | 45 // the XMM registers. The return value is in RAX. |
73 // This calling convention is used on Linux, with GCC, and on Mac OS, | 46 // This calling convention is used on Linux, with GCC, and on Mac OS, |
74 // with GCC. A different convention is used on 64-bit windows, | 47 // with GCC. A different convention is used on 64-bit windows, |
75 // where the first four integer arguments are passed in RCX, RDX, R8 and R9. | 48 // where the first four integer arguments are passed in RCX, RDX, R8 and R9. |
76 | 49 |
77 typedef int (*F0)(); | 50 typedef int (*F0)(); |
78 typedef int (*F1)(int64_t x); | 51 typedef int (*F1)(int64_t x); |
79 typedef int (*F2)(int64_t x, int64_t y); | 52 typedef int (*F2)(int64_t x, int64_t y); |
80 | 53 |
81 #ifdef _WIN64 | 54 #ifdef _WIN64 |
82 static const v8::internal::Register arg1 = rcx; | 55 static const v8::internal::Register arg1 = rcx; |
83 static const v8::internal::Register arg2 = rdx; | 56 static const v8::internal::Register arg2 = rdx; |
84 #else | 57 #else |
85 static const v8::internal::Register arg1 = rdi; | 58 static const v8::internal::Register arg1 = rdi; |
86 static const v8::internal::Register arg2 = rsi; | 59 static const v8::internal::Register arg2 = rsi; |
87 #endif | 60 #endif |
88 | 61 |
89 #define __ assm. | 62 #define __ assm. |
90 | 63 |
91 | 64 |
92 TEST(AssemblerX64ReturnOperation) { | 65 TEST(AssemblerX64ReturnOperation) { |
93 // Allocate an executable page of memory. | 66 // Allocate an executable page of memory. |
94 size_t actual_size; | 67 size_t actual_size; |
95 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 68 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
96 &actual_size, | 69 Assembler::kMinimalBufferSize, |
97 true)); | 70 &actual_size, |
| 71 VirtualMemory::EXECUTABLE)); |
98 CHECK(buffer); | 72 CHECK(buffer); |
99 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 73 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
100 | 74 |
101 // Assemble a simple function that copies argument 2 and returns it. | 75 // Assemble a simple function that copies argument 2 and returns it. |
102 __ movq(rax, arg2); | 76 __ movq(rax, arg2); |
103 __ nop(); | 77 __ nop(); |
104 __ ret(0); | 78 __ ret(0); |
105 | 79 |
106 CodeDesc desc; | 80 CodeDesc desc; |
107 assm.GetCode(&desc); | 81 assm.GetCode(&desc); |
108 // Call the function from C++. | 82 // Call the function from C++. |
109 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 83 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
110 CHECK_EQ(2, result); | 84 CHECK_EQ(2, result); |
111 } | 85 } |
112 | 86 |
113 | 87 |
114 TEST(AssemblerX64StackOperations) { | 88 TEST(AssemblerX64StackOperations) { |
115 // Allocate an executable page of memory. | 89 // Allocate an executable page of memory. |
116 size_t actual_size; | 90 size_t actual_size; |
117 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 91 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
118 &actual_size, | 92 Assembler::kMinimalBufferSize, |
119 true)); | 93 &actual_size, |
| 94 VirtualMemory::EXECUTABLE)); |
120 CHECK(buffer); | 95 CHECK(buffer); |
121 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 96 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
122 | 97 |
123 // Assemble a simple function that copies argument 2 and returns it. | 98 // Assemble a simple function that copies argument 2 and returns it. |
124 // We compile without stack frame pointers, so the gdb debugger shows | 99 // We compile without stack frame pointers, so the gdb debugger shows |
125 // incorrect stack frames when debugging this function (which has them). | 100 // incorrect stack frames when debugging this function (which has them). |
126 __ push(rbp); | 101 __ push(rbp); |
127 __ movq(rbp, rsp); | 102 __ movq(rbp, rsp); |
128 __ push(arg2); // Value at (rbp - 8) | 103 __ push(arg2); // Value at (rbp - 8) |
129 __ push(arg2); // Value at (rbp - 16) | 104 __ push(arg2); // Value at (rbp - 16) |
130 __ push(arg1); // Value at (rbp - 24) | 105 __ push(arg1); // Value at (rbp - 24) |
131 __ pop(rax); | 106 __ pop(rax); |
132 __ pop(rax); | 107 __ pop(rax); |
133 __ pop(rax); | 108 __ pop(rax); |
134 __ pop(rbp); | 109 __ pop(rbp); |
135 __ nop(); | 110 __ nop(); |
136 __ ret(0); | 111 __ ret(0); |
137 | 112 |
138 CodeDesc desc; | 113 CodeDesc desc; |
139 assm.GetCode(&desc); | 114 assm.GetCode(&desc); |
140 // Call the function from C++. | 115 // Call the function from C++. |
141 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 116 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
142 CHECK_EQ(2, result); | 117 CHECK_EQ(2, result); |
143 } | 118 } |
144 | 119 |
145 | 120 |
146 TEST(AssemblerX64ArithmeticOperations) { | 121 TEST(AssemblerX64ArithmeticOperations) { |
147 // Allocate an executable page of memory. | 122 // Allocate an executable page of memory. |
148 size_t actual_size; | 123 size_t actual_size; |
149 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 124 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
150 &actual_size, | 125 Assembler::kMinimalBufferSize, |
151 true)); | 126 &actual_size, |
| 127 VirtualMemory::EXECUTABLE)); |
152 CHECK(buffer); | 128 CHECK(buffer); |
153 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 129 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
154 | 130 |
155 // Assemble a simple function that adds arguments returning the sum. | 131 // Assemble a simple function that adds arguments returning the sum. |
156 __ movq(rax, arg2); | 132 __ movq(rax, arg2); |
157 __ addq(rax, arg1); | 133 __ addq(rax, arg1); |
158 __ ret(0); | 134 __ ret(0); |
159 | 135 |
160 CodeDesc desc; | 136 CodeDesc desc; |
161 assm.GetCode(&desc); | 137 assm.GetCode(&desc); |
162 // Call the function from C++. | 138 // Call the function from C++. |
163 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 139 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
164 CHECK_EQ(5, result); | 140 CHECK_EQ(5, result); |
165 } | 141 } |
166 | 142 |
167 | 143 |
168 TEST(AssemblerX64ImulOperation) { | 144 TEST(AssemblerX64ImulOperation) { |
169 // Allocate an executable page of memory. | 145 // Allocate an executable page of memory. |
170 size_t actual_size; | 146 size_t actual_size; |
171 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 147 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
172 &actual_size, | 148 Assembler::kMinimalBufferSize, |
173 true)); | 149 &actual_size, |
| 150 VirtualMemory::EXECUTABLE)); |
174 CHECK(buffer); | 151 CHECK(buffer); |
175 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 152 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
176 | 153 |
177 // Assemble a simple function that multiplies arguments returning the high | 154 // Assemble a simple function that multiplies arguments returning the high |
178 // word. | 155 // word. |
179 __ movq(rax, arg2); | 156 __ movq(rax, arg2); |
180 __ imul(arg1); | 157 __ imul(arg1); |
181 __ movq(rax, rdx); | 158 __ movq(rax, rdx); |
182 __ ret(0); | 159 __ ret(0); |
183 | 160 |
184 CodeDesc desc; | 161 CodeDesc desc; |
185 assm.GetCode(&desc); | 162 assm.GetCode(&desc); |
186 // Call the function from C++. | 163 // Call the function from C++. |
187 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 164 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
188 CHECK_EQ(0, result); | 165 CHECK_EQ(0, result); |
189 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l); | 166 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l); |
190 CHECK_EQ(1, result); | 167 CHECK_EQ(1, result); |
191 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l); | 168 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l); |
192 CHECK_EQ(-1, result); | 169 CHECK_EQ(-1, result); |
193 } | 170 } |
194 | 171 |
195 | 172 |
196 TEST(AssemblerX64MemoryOperands) { | 173 TEST(AssemblerX64MemoryOperands) { |
197 // Allocate an executable page of memory. | 174 // Allocate an executable page of memory. |
198 size_t actual_size; | 175 size_t actual_size; |
199 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 176 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
200 &actual_size, | 177 Assembler::kMinimalBufferSize, |
201 true)); | 178 &actual_size, |
| 179 VirtualMemory::EXECUTABLE)); |
202 CHECK(buffer); | 180 CHECK(buffer); |
203 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 181 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
204 | 182 |
205 // Assemble a simple function that copies argument 2 and returns it. | 183 // Assemble a simple function that copies argument 2 and returns it. |
206 __ push(rbp); | 184 __ push(rbp); |
207 __ movq(rbp, rsp); | 185 __ movq(rbp, rsp); |
208 | 186 |
209 __ push(arg2); // Value at (rbp - 8) | 187 __ push(arg2); // Value at (rbp - 8) |
210 __ push(arg2); // Value at (rbp - 16) | 188 __ push(arg2); // Value at (rbp - 16) |
211 __ push(arg1); // Value at (rbp - 24) | 189 __ push(arg1); // Value at (rbp - 24) |
(...skipping 11 matching lines...) Expand all Loading... |
223 assm.GetCode(&desc); | 201 assm.GetCode(&desc); |
224 // Call the function from C++. | 202 // Call the function from C++. |
225 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 203 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
226 CHECK_EQ(3, result); | 204 CHECK_EQ(3, result); |
227 } | 205 } |
228 | 206 |
229 | 207 |
230 TEST(AssemblerX64ControlFlow) { | 208 TEST(AssemblerX64ControlFlow) { |
231 // Allocate an executable page of memory. | 209 // Allocate an executable page of memory. |
232 size_t actual_size; | 210 size_t actual_size; |
233 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 211 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
234 &actual_size, | 212 Assembler::kMinimalBufferSize, |
235 true)); | 213 &actual_size, |
| 214 VirtualMemory::EXECUTABLE)); |
236 CHECK(buffer); | 215 CHECK(buffer); |
237 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 216 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
238 | 217 |
239 // Assemble a simple function that copies argument 1 and returns it. | 218 // Assemble a simple function that copies argument 1 and returns it. |
240 __ push(rbp); | 219 __ push(rbp); |
241 | 220 |
242 __ movq(rbp, rsp); | 221 __ movq(rbp, rsp); |
243 __ movq(rax, arg1); | 222 __ movq(rax, arg1); |
244 Label target; | 223 Label target; |
245 __ jmp(&target); | 224 __ jmp(&target); |
246 __ movq(rax, arg2); | 225 __ movq(rax, arg2); |
247 __ bind(&target); | 226 __ bind(&target); |
248 __ pop(rbp); | 227 __ pop(rbp); |
249 __ ret(0); | 228 __ ret(0); |
250 | 229 |
251 CodeDesc desc; | 230 CodeDesc desc; |
252 assm.GetCode(&desc); | 231 assm.GetCode(&desc); |
253 // Call the function from C++. | 232 // Call the function from C++. |
254 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 233 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
255 CHECK_EQ(3, result); | 234 CHECK_EQ(3, result); |
256 } | 235 } |
257 | 236 |
258 | 237 |
259 TEST(AssemblerX64LoopImmediates) { | 238 TEST(AssemblerX64LoopImmediates) { |
260 // Allocate an executable page of memory. | 239 // Allocate an executable page of memory. |
261 size_t actual_size; | 240 size_t actual_size; |
262 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 241 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
263 &actual_size, | 242 Assembler::kMinimalBufferSize, |
264 true)); | 243 &actual_size, |
| 244 VirtualMemory::EXECUTABLE)); |
265 CHECK(buffer); | 245 CHECK(buffer); |
266 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 246 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
267 // Assemble two loops using rax as counter, and verify the ending counts. | 247 // Assemble two loops using rax as counter, and verify the ending counts. |
268 Label Fail; | 248 Label Fail; |
269 __ movq(rax, Immediate(-3)); | 249 __ movq(rax, Immediate(-3)); |
270 Label Loop1_test; | 250 Label Loop1_test; |
271 Label Loop1_body; | 251 Label Loop1_body; |
272 __ jmp(&Loop1_test); | 252 __ jmp(&Loop1_test); |
273 __ bind(&Loop1_body); | 253 __ bind(&Loop1_body); |
274 __ addq(rax, Immediate(7)); | 254 __ addq(rax, Immediate(7)); |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 | 491 |
512 // The mask should be 0b1000. | 492 // The mask should be 0b1000. |
513 CHECK_EQ(8, result->Int32Value()); | 493 CHECK_EQ(8, result->Int32Value()); |
514 } | 494 } |
515 | 495 |
516 #undef ELEMENT_COUNT | 496 #undef ELEMENT_COUNT |
517 #endif // __GNUC__ | 497 #endif // __GNUC__ |
518 | 498 |
519 | 499 |
520 #undef __ | 500 #undef __ |
OLD | NEW |