v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-assembler-x64.cc
Go to the documentation of this file.
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 
39 using v8::internal::Code;
42 using v8::internal::Immediate;
44 using v8::internal::Label;
45 using v8::internal::OS;
46 using v8::internal::Operand;
47 using v8::internal::byte;
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;
65 
66 // Test the x64 assembler by compiling some simple functions into
67 // a buffer and executing them. These tests do not initialize the
68 // V8 library, create a context, or use any V8 objects.
69 // The AMD64 calling convention is used, with the first six arguments
70 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
71 // the XMM registers. The return value is in RAX.
72 // This calling convention is used on Linux, with GCC, and on Mac OS,
73 // with GCC. A different convention is used on 64-bit windows,
74 // where the first four integer arguments are passed in RCX, RDX, R8 and R9.
75 
76 typedef int (*F0)();
77 typedef int (*F1)(int64_t x);
78 typedef int (*F2)(int64_t x, int64_t y);
79 
80 #ifdef _WIN64
81 static const v8::internal::Register arg1 = rcx;
82 static const v8::internal::Register arg2 = rdx;
83 #else
84 static const v8::internal::Register arg1 = rdi;
85 static const v8::internal::Register arg2 = rsi;
86 #endif
87 
88 #define __ assm.
89 
90 
92 
93 
94 static void InitializeVM() {
95  if (env.IsEmpty()) {
96  env = v8::Context::New();
97  }
98 }
99 
100 
101 TEST(AssemblerX64ReturnOperation) {
102  OS::SetUp();
103  // Allocate an executable page of memory.
104  size_t actual_size;
105  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
106  &actual_size,
107  true));
108  CHECK(buffer);
109  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
110 
111  // Assemble a simple function that copies argument 2 and returns it.
112  __ movq(rax, arg2);
113  __ nop();
114  __ ret(0);
115 
116  CodeDesc desc;
117  assm.GetCode(&desc);
118  // Call the function from C++.
119  int result = FUNCTION_CAST<F2>(buffer)(3, 2);
120  CHECK_EQ(2, result);
121 }
122 
123 TEST(AssemblerX64StackOperations) {
124  OS::SetUp();
125  // Allocate an executable page of memory.
126  size_t actual_size;
127  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
128  &actual_size,
129  true));
130  CHECK(buffer);
131  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
132 
133  // Assemble a simple function that copies argument 2 and returns it.
134  // We compile without stack frame pointers, so the gdb debugger shows
135  // incorrect stack frames when debugging this function (which has them).
136  __ push(rbp);
137  __ movq(rbp, rsp);
138  __ push(arg2); // Value at (rbp - 8)
139  __ push(arg2); // Value at (rbp - 16)
140  __ push(arg1); // Value at (rbp - 24)
141  __ pop(rax);
142  __ pop(rax);
143  __ pop(rax);
144  __ pop(rbp);
145  __ nop();
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(2, result);
153 }
154 
155 TEST(AssemblerX64ArithmeticOperations) {
156  OS::SetUp();
157  // Allocate an executable page of memory.
158  size_t actual_size;
159  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
160  &actual_size,
161  true));
162  CHECK(buffer);
163  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
164 
165  // Assemble a simple function that adds arguments returning the sum.
166  __ movq(rax, arg2);
167  __ addq(rax, arg1);
168  __ ret(0);
169 
170  CodeDesc desc;
171  assm.GetCode(&desc);
172  // Call the function from C++.
173  int result = FUNCTION_CAST<F2>(buffer)(3, 2);
174  CHECK_EQ(5, result);
175 }
176 
177 TEST(AssemblerX64ImulOperation) {
178  OS::SetUp();
179  // Allocate an executable page of memory.
180  size_t actual_size;
181  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
182  &actual_size,
183  true));
184  CHECK(buffer);
185  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
186 
187  // Assemble a simple function that multiplies arguments returning the high
188  // word.
189  __ movq(rax, arg2);
190  __ imul(arg1);
191  __ movq(rax, rdx);
192  __ ret(0);
193 
194  CodeDesc desc;
195  assm.GetCode(&desc);
196  // Call the function from C++.
197  int result = FUNCTION_CAST<F2>(buffer)(3, 2);
198  CHECK_EQ(0, result);
199  result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l);
200  CHECK_EQ(1, result);
201  result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l);
202  CHECK_EQ(-1, result);
203 }
204 
205 TEST(AssemblerX64MemoryOperands) {
206  OS::SetUp();
207  // Allocate an executable page of memory.
208  size_t actual_size;
209  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
210  &actual_size,
211  true));
212  CHECK(buffer);
213  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
214 
215  // Assemble a simple function that copies argument 2 and returns it.
216  __ push(rbp);
217  __ movq(rbp, rsp);
218 
219  __ push(arg2); // Value at (rbp - 8)
220  __ push(arg2); // Value at (rbp - 16)
221  __ push(arg1); // Value at (rbp - 24)
222 
223  const int kStackElementSize = 8;
224  __ movq(rax, Operand(rbp, -3 * kStackElementSize));
225  __ pop(arg2);
226  __ pop(arg2);
227  __ pop(arg2);
228  __ pop(rbp);
229  __ nop();
230  __ ret(0);
231 
232  CodeDesc desc;
233  assm.GetCode(&desc);
234  // Call the function from C++.
235  int result = FUNCTION_CAST<F2>(buffer)(3, 2);
236  CHECK_EQ(3, result);
237 }
238 
239 TEST(AssemblerX64ControlFlow) {
240  OS::SetUp();
241  // Allocate an executable page of memory.
242  size_t actual_size;
243  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
244  &actual_size,
245  true));
246  CHECK(buffer);
247  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
248 
249  // Assemble a simple function that copies argument 1 and returns it.
250  __ push(rbp);
251 
252  __ movq(rbp, rsp);
253  __ movq(rax, arg1);
254  Label target;
255  __ jmp(&target);
256  __ movq(rax, arg2);
257  __ bind(&target);
258  __ pop(rbp);
259  __ ret(0);
260 
261  CodeDesc desc;
262  assm.GetCode(&desc);
263  // Call the function from C++.
264  int result = FUNCTION_CAST<F2>(buffer)(3, 2);
265  CHECK_EQ(3, result);
266 }
267 
268 TEST(AssemblerX64LoopImmediates) {
269  OS::SetUp();
270  // Allocate an executable page of memory.
271  size_t actual_size;
272  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
273  &actual_size,
274  true));
275  CHECK(buffer);
276  Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
277  // Assemble two loops using rax as counter, and verify the ending counts.
278  Label Fail;
279  __ movq(rax, Immediate(-3));
280  Label Loop1_test;
281  Label Loop1_body;
282  __ jmp(&Loop1_test);
283  __ bind(&Loop1_body);
284  __ addq(rax, Immediate(7));
285  __ bind(&Loop1_test);
286  __ cmpq(rax, Immediate(20));
287  __ j(less_equal, &Loop1_body);
288  // Did the loop terminate with the expected value?
289  __ cmpq(rax, Immediate(25));
290  __ j(not_equal, &Fail);
291 
292  Label Loop2_test;
293  Label Loop2_body;
294  __ movq(rax, Immediate(0x11FEED00));
295  __ jmp(&Loop2_test);
296  __ bind(&Loop2_body);
297  __ addq(rax, Immediate(-0x1100));
298  __ bind(&Loop2_test);
299  __ cmpq(rax, Immediate(0x11FE8000));
300  __ j(greater, &Loop2_body);
301  // Did the loop terminate with the expected value?
302  __ cmpq(rax, Immediate(0x11FE7600));
303  __ j(not_equal, &Fail);
304 
305  __ movq(rax, Immediate(1));
306  __ ret(0);
307  __ bind(&Fail);
308  __ movq(rax, Immediate(0));
309  __ ret(0);
310 
311  CodeDesc desc;
312  assm.GetCode(&desc);
313  // Call the function from C++.
314  int result = FUNCTION_CAST<F0>(buffer)();
315  CHECK_EQ(1, result);
316 }
317 
318 
319 TEST(OperandRegisterDependency) {
320  int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
321  for (int i = 0; i < 4; i++) {
322  int offset = offsets[i];
323  CHECK(Operand(rax, offset).AddressUsesRegister(rax));
324  CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
325  CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
326 
327  CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
328  CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
329  CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
330 
331  CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
332  CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
333  CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
334  CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
335  CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
336  CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
337 
338  CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
339  CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
340  CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
341 
342  CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
343  CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
344  CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
345 
346  CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
347  CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
348  CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
349  CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
350  CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
351  CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
352 
353  CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
354  CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
355  CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
356  CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
357  CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
358  }
359 }
360 
361 
362 TEST(AssemblerX64LabelChaining) {
363  // Test chaining of label usages within instructions (issue 1644).
364  v8::HandleScope scope;
365  Assembler assm(Isolate::Current(), NULL, 0);
366 
367  Label target;
368  __ j(equal, &target);
369  __ j(not_equal, &target);
370  __ bind(&target);
371  __ nop();
372 }
373 
374 
375 TEST(AssemblerMultiByteNop) {
376  InitializeVM();
377  v8::HandleScope scope;
378  v8::internal::byte buffer[1024];
379  Assembler assm(Isolate::Current(), buffer, sizeof(buffer));
380  __ push(rbx);
381  __ push(rcx);
382  __ push(rdx);
383  __ push(rdi);
384  __ push(rsi);
385  __ movq(rax, Immediate(1));
386  __ movq(rbx, Immediate(2));
387  __ movq(rcx, Immediate(3));
388  __ movq(rdx, Immediate(4));
389  __ movq(rdi, Immediate(5));
390  __ movq(rsi, Immediate(6));
391  for (int i = 0; i < 16; i++) {
392  int before = assm.pc_offset();
393  __ Nop(i);
394  CHECK_EQ(assm.pc_offset() - before, i);
395  }
396 
397  Label fail;
398  __ cmpq(rax, Immediate(1));
399  __ j(not_equal, &fail);
400  __ cmpq(rbx, Immediate(2));
401  __ j(not_equal, &fail);
402  __ cmpq(rcx, Immediate(3));
403  __ j(not_equal, &fail);
404  __ cmpq(rdx, Immediate(4));
405  __ j(not_equal, &fail);
406  __ cmpq(rdi, Immediate(5));
407  __ j(not_equal, &fail);
408  __ cmpq(rsi, Immediate(6));
409  __ j(not_equal, &fail);
410  __ movq(rax, Immediate(42));
411  __ pop(rsi);
412  __ pop(rdi);
413  __ pop(rdx);
414  __ pop(rcx);
415  __ pop(rbx);
416  __ ret(0);
417  __ bind(&fail);
418  __ movq(rax, Immediate(13));
419  __ pop(rsi);
420  __ pop(rdi);
421  __ pop(rdx);
422  __ pop(rcx);
423  __ pop(rbx);
424  __ ret(0);
425 
426  CodeDesc desc;
427  assm.GetCode(&desc);
428  Code* code = Code::cast(HEAP->CreateCode(
429  desc,
430  Code::ComputeFlags(Code::STUB),
432  HEAP->undefined_value()))->ToObjectChecked());
433  CHECK(code->IsCode());
434 
435  F0 f = FUNCTION_CAST<F0>(code->entry());
436  int res = f();
437  CHECK_EQ(42, res);
438 }
439 
440 
441 
442 
443 #undef __
const Register rdx
int(* F0)()
unsigned char byte
Definition: disasm.h:33
#define CHECK_EQ(expected, value)
Definition: checks.h:219
v8::Handle< v8::Value > Fail(const v8::Arguments &args)
const Register rbp
const Register rsi
#define CHECK(condition)
Definition: checks.h:56
int(* F1)(int64_t x)
uint8_t byte
Definition: globals.h:171
TEST(AssemblerX64ReturnOperation)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
void GetCode(CodeDesc *desc)
const Register r9
const Register rbx
const Register rsp
int(* F2)(int64_t x, int64_t y)
const Register rax
const Register r13
const Register rdi
#define __
const Register r8
const Register rcx
#define HEAP
Definition: isolate.h:1408
bool IsEmpty() const
Definition: v8.h:208
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4308
const Register r15
F FUNCTION_CAST(Address addr)
Definition: globals.h:314