1// Copyright 2011 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 "src/v8.h"
31
32#include "src/base/platform/platform.h"
33#include "src/base/utils/random-number-generator.h"
34#include "src/disassembler.h"
35#include "src/factory.h"
36#include "src/macro-assembler.h"
37#include "src/ostreams.h"
38#include "test/cctest/cctest.h"
39
40using namespace v8::internal;
41
42
43typedef int (*F0)();
44typedef int (*F1)(int x);
45typedef int (*F2)(int x, int y);
46
47
48#define __ assm.
49
50TEST(AssemblerIa320) {
51  CcTest::InitializeVM();
52  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
53  HandleScope scope(isolate);
54
55  v8::internal::byte buffer[256];
56  Assembler assm(isolate, buffer, sizeof buffer);
57
58  __ mov(eax, Operand(esp, 4));
59  __ add(eax, Operand(esp, 8));
60  __ ret(0);
61
62  CodeDesc desc;
63  assm.GetCode(&desc);
64  Handle<Code> code = isolate->factory()->NewCode(
65      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
66#ifdef OBJECT_PRINT
67  OFStream os(stdout);
68  code->Print(os);
69#endif
70  F2 f = FUNCTION_CAST<F2>(code->entry());
71  int res = f(3, 4);
72  ::printf("f() = %d\n", res);
73  CHECK_EQ(7, res);
74}
75
76
77TEST(AssemblerIa321) {
78  CcTest::InitializeVM();
79  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
80  HandleScope scope(isolate);
81
82  v8::internal::byte buffer[256];
83  Assembler assm(isolate, buffer, sizeof buffer);
84  Label L, C;
85
86  __ mov(edx, Operand(esp, 4));
87  __ xor_(eax, eax);  // clear eax
88  __ jmp(&C);
89
90  __ bind(&L);
91  __ add(eax, edx);
92  __ sub(edx, Immediate(1));
93
94  __ bind(&C);
95  __ test(edx, edx);
96  __ j(not_zero, &L);
97  __ ret(0);
98
99  CodeDesc desc;
100  assm.GetCode(&desc);
101  Handle<Code> code = isolate->factory()->NewCode(
102      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
103#ifdef OBJECT_PRINT
104  OFStream os(stdout);
105  code->Print(os);
106#endif
107  F1 f = FUNCTION_CAST<F1>(code->entry());
108  int res = f(100);
109  ::printf("f() = %d\n", res);
110  CHECK_EQ(5050, res);
111}
112
113
114TEST(AssemblerIa322) {
115  CcTest::InitializeVM();
116  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
117  HandleScope scope(isolate);
118
119  v8::internal::byte buffer[256];
120  Assembler assm(isolate, buffer, sizeof buffer);
121  Label L, C;
122
123  __ mov(edx, Operand(esp, 4));
124  __ mov(eax, 1);
125  __ jmp(&C);
126
127  __ bind(&L);
128  __ imul(eax, edx);
129  __ sub(edx, Immediate(1));
130
131  __ bind(&C);
132  __ test(edx, edx);
133  __ j(not_zero, &L);
134  __ ret(0);
135
136  // some relocated stuff here, not executed
137  __ mov(eax, isolate->factory()->true_value());
138  __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
139
140  CodeDesc desc;
141  assm.GetCode(&desc);
142  Handle<Code> code = isolate->factory()->NewCode(
143      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
144#ifdef OBJECT_PRINT
145  OFStream os(stdout);
146  code->Print(os);
147#endif
148  F1 f = FUNCTION_CAST<F1>(code->entry());
149  int res = f(10);
150  ::printf("f() = %d\n", res);
151  CHECK_EQ(3628800, res);
152}
153
154
155typedef int (*F3)(float x);
156
157typedef int (*F4)(double x);
158
159static int baz = 42;
160TEST(AssemblerIa325) {
161  CcTest::InitializeVM();
162  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
163  HandleScope scope(isolate);
164
165  v8::internal::byte buffer[256];
166  Assembler assm(isolate, buffer, sizeof buffer);
167
168  __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32));
169  __ ret(0);
170
171  CodeDesc desc;
172  assm.GetCode(&desc);
173  Handle<Code> code = isolate->factory()->NewCode(
174      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
175  F0 f = FUNCTION_CAST<F0>(code->entry());
176  int res = f();
177  CHECK_EQ(42, res);
178}
179
180
181typedef int (*F7)(double x, double y);
182
183TEST(AssemblerIa329) {
184  CcTest::InitializeVM();
185  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
186  HandleScope scope(isolate);
187  v8::internal::byte buffer[256];
188  MacroAssembler assm(isolate, buffer, sizeof(buffer),
189                      v8::internal::CodeObjectRequired::kYes);
190  enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
191  Label equal_l, less_l, greater_l, nan_l;
192  __ fld_d(Operand(esp, 3 * kPointerSize));
193  __ fld_d(Operand(esp, 1 * kPointerSize));
194  __ FCmp();
195  __ j(parity_even, &nan_l);
196  __ j(equal, &equal_l);
197  __ j(below, &less_l);
198  __ j(above, &greater_l);
199
200  __ mov(eax, kUndefined);
201  __ ret(0);
202
203  __ bind(&equal_l);
204  __ mov(eax, kEqual);
205  __ ret(0);
206
207  __ bind(&greater_l);
208  __ mov(eax, kGreater);
209  __ ret(0);
210
211  __ bind(&less_l);
212  __ mov(eax, kLess);
213  __ ret(0);
214
215  __ bind(&nan_l);
216  __ mov(eax, kNaN);
217  __ ret(0);
218
219
220  CodeDesc desc;
221  assm.GetCode(&desc);
222  Handle<Code> code = isolate->factory()->NewCode(
223      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
224#ifdef OBJECT_PRINT
225  OFStream os(stdout);
226  code->Print(os);
227#endif
228
229  F7 f = FUNCTION_CAST<F7>(code->entry());
230  CHECK_EQ(kLess, f(1.1, 2.2));
231  CHECK_EQ(kEqual, f(2.2, 2.2));
232  CHECK_EQ(kGreater, f(3.3, 2.2));
233  CHECK_EQ(kNaN, f(std::numeric_limits<double>::quiet_NaN(), 1.1));
234}
235
236
237TEST(AssemblerIa3210) {
238  // Test chaining of label usages within instructions (issue 1644).
239  CcTest::InitializeVM();
240  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
241  HandleScope scope(isolate);
242  Assembler assm(isolate, NULL, 0);
243
244  Label target;
245  __ j(equal, &target);
246  __ j(not_equal, &target);
247  __ bind(&target);
248  __ nop();
249}
250
251
252TEST(AssemblerMultiByteNop) {
253  CcTest::InitializeVM();
254  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
255  HandleScope scope(isolate);
256  v8::internal::byte buffer[1024];
257  Assembler assm(isolate, buffer, sizeof(buffer));
258  __ push(ebx);
259  __ push(ecx);
260  __ push(edx);
261  __ push(edi);
262  __ push(esi);
263  __ mov(eax, 1);
264  __ mov(ebx, 2);
265  __ mov(ecx, 3);
266  __ mov(edx, 4);
267  __ mov(edi, 5);
268  __ mov(esi, 6);
269  for (int i = 0; i < 16; i++) {
270    int before = assm.pc_offset();
271    __ Nop(i);
272    CHECK_EQ(assm.pc_offset() - before, i);
273  }
274
275  Label fail;
276  __ cmp(eax, 1);
277  __ j(not_equal, &fail);
278  __ cmp(ebx, 2);
279  __ j(not_equal, &fail);
280  __ cmp(ecx, 3);
281  __ j(not_equal, &fail);
282  __ cmp(edx, 4);
283  __ j(not_equal, &fail);
284  __ cmp(edi, 5);
285  __ j(not_equal, &fail);
286  __ cmp(esi, 6);
287  __ j(not_equal, &fail);
288  __ mov(eax, 42);
289  __ pop(esi);
290  __ pop(edi);
291  __ pop(edx);
292  __ pop(ecx);
293  __ pop(ebx);
294  __ ret(0);
295  __ bind(&fail);
296  __ mov(eax, 13);
297  __ pop(esi);
298  __ pop(edi);
299  __ pop(edx);
300  __ pop(ecx);
301  __ pop(ebx);
302  __ ret(0);
303
304  CodeDesc desc;
305  assm.GetCode(&desc);
306  Handle<Code> code = isolate->factory()->NewCode(
307      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
308  CHECK(code->IsCode());
309
310  F0 f = FUNCTION_CAST<F0>(code->entry());
311  int res = f();
312  CHECK_EQ(42, res);
313}
314
315
316TEST(AssemblerIa32JumpTables1) {
317  // Test jump tables with forward jumps.
318  CcTest::InitializeVM();
319  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
320  HandleScope scope(isolate);
321  Assembler assm(isolate, nullptr, 0);
322
323  const int kNumCases = 512;
324  int values[kNumCases];
325  isolate->random_number_generator()->NextBytes(values, sizeof(values));
326  Label labels[kNumCases];
327
328  Label done, table;
329  __ mov(eax, Operand(esp, 4));
330  __ jmp(Operand::JumpTable(eax, times_4, &table));
331  __ ud2();
332  __ bind(&table);
333  for (int i = 0; i < kNumCases; ++i) {
334    __ dd(&labels[i]);
335  }
336
337  for (int i = 0; i < kNumCases; ++i) {
338    __ bind(&labels[i]);
339    __ mov(eax, Immediate(values[i]));
340    __ jmp(&done);
341  }
342
343  __ bind(&done);
344  __ ret(0);
345
346  CodeDesc desc;
347  assm.GetCode(&desc);
348  Handle<Code> code = isolate->factory()->NewCode(
349      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
350#ifdef OBJECT_PRINT
351  OFStream os(stdout);
352  code->Print(os);
353#endif
354  F1 f = FUNCTION_CAST<F1>(code->entry());
355  for (int i = 0; i < kNumCases; ++i) {
356    int res = f(i);
357    ::printf("f(%d) = %d\n", i, res);
358    CHECK_EQ(values[i], res);
359  }
360}
361
362
363TEST(AssemblerIa32JumpTables2) {
364  // Test jump tables with backward jumps.
365  CcTest::InitializeVM();
366  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
367  HandleScope scope(isolate);
368  Assembler assm(isolate, nullptr, 0);
369
370  const int kNumCases = 512;
371  int values[kNumCases];
372  isolate->random_number_generator()->NextBytes(values, sizeof(values));
373  Label labels[kNumCases];
374
375  Label done, table;
376  __ mov(eax, Operand(esp, 4));
377  __ jmp(Operand::JumpTable(eax, times_4, &table));
378  __ ud2();
379
380  for (int i = 0; i < kNumCases; ++i) {
381    __ bind(&labels[i]);
382    __ mov(eax, Immediate(values[i]));
383    __ jmp(&done);
384  }
385
386  __ bind(&table);
387  for (int i = 0; i < kNumCases; ++i) {
388    __ dd(&labels[i]);
389  }
390
391  __ bind(&done);
392  __ ret(0);
393
394  CodeDesc desc;
395  assm.GetCode(&desc);
396  Handle<Code> code = isolate->factory()->NewCode(
397      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
398#ifdef OBJECT_PRINT
399  OFStream os(stdout);
400  code->Print(os);
401#endif
402  F1 f = FUNCTION_CAST<F1>(code->entry());
403  for (int i = 0; i < kNumCases; ++i) {
404    int res = f(i);
405    ::printf("f(%d) = %d\n", i, res);
406    CHECK_EQ(values[i], res);
407  }
408}
409
410#undef __
411