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
38namespace i = v8::internal;
39using i::Address;
40using i::Assembler;
41using i::CodeDesc;
42using i::Condition;
43using i::FUNCTION_CAST;
44using i::HandleScope;
45using i::Immediate;
46using i::Isolate;
47using i::Label;
48using i::MacroAssembler;
49using i::OS;
50using i::Operand;
51using i::RelocInfo;
52using i::Representation;
53using i::Smi;
54using i::SmiIndex;
55using i::byte;
56using i::carry;
57using i::greater;
58using i::greater_equal;
59using i::kIntSize;
60using i::kPointerSize;
61using i::kSmiTagMask;
62using i::kSmiValueSize;
63using i::less_equal;
64using i::negative;
65using i::not_carry;
66using i::not_equal;
67using i::equal;
68using i::not_zero;
69using i::positive;
70using i::r11;
71using i::r13;
72using i::r14;
73using i::r15;
74using i::r8;
75using i::r9;
76using i::rax;
77using i::rbp;
78using i::rbx;
79using i::rcx;
80using i::rdi;
81using i::rdx;
82using i::rsi;
83using i::rsp;
84using i::times_pointer_size;
85
86// Test the x64 assembler by compiling some simple functions into
87// a buffer and executing them.  These tests do not initialize the
88// V8 library, create a context, or use any V8 objects.
89// The AMD64 calling convention is used, with the first five arguments
90// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in
91// the XMM registers.  The return value is in RAX.
92// This calling convention is used on Linux, with GCC, and on Mac OS,
93// with GCC.  A different convention is used on 64-bit windows.
94
95typedef int (*F0)();
96
97#define __ masm->
98
99
100static void EntryCode(MacroAssembler* masm) {
101  // Smi constant register is callee save.
102  __ push(i::kSmiConstantRegister);
103  __ push(i::kRootRegister);
104  __ InitializeSmiConstantRegister();
105  __ InitializeRootRegister();
106}
107
108
109static void ExitCode(MacroAssembler* masm) {
110  // Return -1 if kSmiConstantRegister was clobbered during the test.
111  __ Move(rdx, Smi::FromInt(1));
112  __ cmpq(rdx, i::kSmiConstantRegister);
113  __ movq(rdx, Immediate(-1));
114  __ cmovq(not_equal, rax, rdx);
115  __ pop(i::kRootRegister);
116  __ pop(i::kSmiConstantRegister);
117}
118
119
120TEST(Smi) {
121  // Check that C++ Smi operations work as expected.
122  int64_t test_numbers[] = {
123      0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257,
124      Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1,
125      Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1
126  };
127  int test_number_count = 15;
128  for (int i = 0; i < test_number_count; i++) {
129    int64_t number = test_numbers[i];
130    bool is_valid = Smi::IsValid(number);
131    bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue;
132    CHECK_EQ(is_in_range, is_valid);
133    if (is_valid) {
134      Smi* smi_from_intptr = Smi::FromIntptr(number);
135      if (static_cast<int>(number) == number) {  // Is a 32-bit int.
136        Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number));
137        CHECK_EQ(smi_from_int, smi_from_intptr);
138      }
139      int64_t smi_value = smi_from_intptr->value();
140      CHECK_EQ(number, smi_value);
141    }
142  }
143}
144
145
146static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) {
147  __ movl(rax, Immediate(id));
148  __ Move(rcx, value);
149  __ Set(rdx, reinterpret_cast<intptr_t>(value));
150  __ cmpq(rcx, rdx);
151  __ j(not_equal, exit);
152}
153
154
155// Test that we can move a Smi value literally into a register.
156TEST(SmiMove) {
157  i::V8::Initialize(NULL);
158  // Allocate an executable page of memory.
159  size_t actual_size;
160  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
161                                                   &actual_size,
162                                                   true));
163  CHECK(buffer);
164  Isolate* isolate = CcTest::i_isolate();
165  HandleScope handles(isolate);
166  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
167  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
168  EntryCode(masm);
169  Label exit;
170
171  TestMoveSmi(masm, &exit, 1, Smi::FromInt(0));
172  TestMoveSmi(masm, &exit, 2, Smi::FromInt(127));
173  TestMoveSmi(masm, &exit, 3, Smi::FromInt(128));
174  TestMoveSmi(masm, &exit, 4, Smi::FromInt(255));
175  TestMoveSmi(masm, &exit, 5, Smi::FromInt(256));
176  TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue));
177  TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1));
178  TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128));
179  TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129));
180  TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256));
181  TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257));
182  TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue));
183
184  __ xor_(rax, rax);  // Success.
185  __ bind(&exit);
186  ExitCode(masm);
187  __ ret(0);
188
189  CodeDesc desc;
190  masm->GetCode(&desc);
191  // Call the function from C++.
192  int result = FUNCTION_CAST<F0>(buffer)();
193  CHECK_EQ(0, result);
194}
195
196
197void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
198  __ Move(rcx, Smi::FromInt(x));
199  __ movq(r8, rcx);
200  __ Move(rdx, Smi::FromInt(y));
201  __ movq(r9, rdx);
202  __ SmiCompare(rcx, rdx);
203  if (x < y) {
204    __ movl(rax, Immediate(id + 1));
205    __ j(greater_equal, exit);
206  } else if (x > y) {
207    __ movl(rax, Immediate(id + 2));
208    __ j(less_equal, exit);
209  } else {
210    ASSERT_EQ(x, y);
211    __ movl(rax, Immediate(id + 3));
212    __ j(not_equal, exit);
213  }
214  __ movl(rax, Immediate(id + 4));
215  __ cmpq(rcx, r8);
216  __ j(not_equal, exit);
217  __ incq(rax);
218  __ cmpq(rdx, r9);
219  __ j(not_equal, exit);
220
221  if (x != y) {
222    __ SmiCompare(rdx, rcx);
223    if (y < x) {
224      __ movl(rax, Immediate(id + 9));
225      __ j(greater_equal, exit);
226    } else {
227      ASSERT(y > x);
228      __ movl(rax, Immediate(id + 10));
229      __ j(less_equal, exit);
230    }
231  } else {
232    __ cmpq(rcx, rcx);
233    __ movl(rax, Immediate(id + 11));
234    __ j(not_equal, exit);
235    __ incq(rax);
236    __ cmpq(rcx, r8);
237    __ j(not_equal, exit);
238  }
239}
240
241
242// Test that we can compare smis for equality (and more).
243TEST(SmiCompare) {
244  i::V8::Initialize(NULL);
245  // Allocate an executable page of memory.
246  size_t actual_size;
247  byte* buffer =
248      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
249                                      &actual_size,
250                                      true));
251  CHECK(buffer);
252  Isolate* isolate = CcTest::i_isolate();
253  HandleScope handles(isolate);
254  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
255
256  MacroAssembler* masm = &assembler;
257  EntryCode(masm);
258  Label exit;
259
260  TestSmiCompare(masm, &exit, 0x10, 0, 0);
261  TestSmiCompare(masm, &exit, 0x20, 0, 1);
262  TestSmiCompare(masm, &exit, 0x30, 1, 0);
263  TestSmiCompare(masm, &exit, 0x40, 1, 1);
264  TestSmiCompare(masm, &exit, 0x50, 0, -1);
265  TestSmiCompare(masm, &exit, 0x60, -1, 0);
266  TestSmiCompare(masm, &exit, 0x70, -1, -1);
267  TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue);
268  TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0);
269  TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue);
270  TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0);
271  TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue);
272  TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1);
273  TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue);
274  TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1);
275  TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue);
276  TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue);
277  TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue);
278  TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue);
279
280  __ xor_(rax, rax);  // Success.
281  __ bind(&exit);
282  ExitCode(masm);
283  __ ret(0);
284
285  CodeDesc desc;
286  masm->GetCode(&desc);
287  // Call the function from C++.
288  int result = FUNCTION_CAST<F0>(buffer)();
289  CHECK_EQ(0, result);
290}
291
292
293
294TEST(Integer32ToSmi) {
295  i::V8::Initialize(NULL);
296  // Allocate an executable page of memory.
297  size_t actual_size;
298  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
299                                                 &actual_size,
300                                                 true));
301  CHECK(buffer);
302  Isolate* isolate = CcTest::i_isolate();
303  HandleScope handles(isolate);
304  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
305
306  MacroAssembler* masm = &assembler;
307  EntryCode(masm);
308  Label exit;
309
310  __ movq(rax, Immediate(1));  // Test number.
311  __ movl(rcx, Immediate(0));
312  __ Integer32ToSmi(rcx, rcx);
313  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
314  __ cmpq(rcx, rdx);
315  __ j(not_equal, &exit);
316
317  __ movq(rax, Immediate(2));  // Test number.
318  __ movl(rcx, Immediate(1024));
319  __ Integer32ToSmi(rcx, rcx);
320  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
321  __ cmpq(rcx, rdx);
322  __ j(not_equal, &exit);
323
324  __ movq(rax, Immediate(3));  // Test number.
325  __ movl(rcx, Immediate(-1));
326  __ Integer32ToSmi(rcx, rcx);
327  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
328  __ cmpq(rcx, rdx);
329  __ j(not_equal, &exit);
330
331  __ movq(rax, Immediate(4));  // Test number.
332  __ movl(rcx, Immediate(Smi::kMaxValue));
333  __ Integer32ToSmi(rcx, rcx);
334  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
335  __ cmpq(rcx, rdx);
336  __ j(not_equal, &exit);
337
338  __ movq(rax, Immediate(5));  // Test number.
339  __ movl(rcx, Immediate(Smi::kMinValue));
340  __ Integer32ToSmi(rcx, rcx);
341  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
342  __ cmpq(rcx, rdx);
343  __ j(not_equal, &exit);
344
345  // Different target register.
346
347  __ movq(rax, Immediate(6));  // Test number.
348  __ movl(rcx, Immediate(0));
349  __ Integer32ToSmi(r8, rcx);
350  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
351  __ cmpq(r8, rdx);
352  __ j(not_equal, &exit);
353
354  __ movq(rax, Immediate(7));  // Test number.
355  __ movl(rcx, Immediate(1024));
356  __ Integer32ToSmi(r8, rcx);
357  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
358  __ cmpq(r8, rdx);
359  __ j(not_equal, &exit);
360
361  __ movq(rax, Immediate(8));  // Test number.
362  __ movl(rcx, Immediate(-1));
363  __ Integer32ToSmi(r8, rcx);
364  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
365  __ cmpq(r8, rdx);
366  __ j(not_equal, &exit);
367
368  __ movq(rax, Immediate(9));  // Test number.
369  __ movl(rcx, Immediate(Smi::kMaxValue));
370  __ Integer32ToSmi(r8, rcx);
371  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
372  __ cmpq(r8, rdx);
373  __ j(not_equal, &exit);
374
375  __ movq(rax, Immediate(10));  // Test number.
376  __ movl(rcx, Immediate(Smi::kMinValue));
377  __ Integer32ToSmi(r8, rcx);
378  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
379  __ cmpq(r8, rdx);
380  __ j(not_equal, &exit);
381
382
383  __ xor_(rax, rax);  // Success.
384  __ bind(&exit);
385  ExitCode(masm);
386  __ ret(0);
387
388  CodeDesc desc;
389  masm->GetCode(&desc);
390  // Call the function from C++.
391  int result = FUNCTION_CAST<F0>(buffer)();
392  CHECK_EQ(0, result);
393}
394
395
396void TestI64PlusConstantToSmi(MacroAssembler* masm,
397                              Label* exit,
398                              int id,
399                              int64_t x,
400                              int y) {
401  int64_t result = x + y;
402  ASSERT(Smi::IsValid(result));
403  __ movl(rax, Immediate(id));
404  __ Move(r8, Smi::FromInt(static_cast<int>(result)));
405  __ movq(rcx, x);
406  __ movq(r11, rcx);
407  __ Integer64PlusConstantToSmi(rdx, rcx, y);
408  __ cmpq(rdx, r8);
409  __ j(not_equal, exit);
410
411  __ incq(rax);
412  __ cmpq(r11, rcx);
413  __ j(not_equal, exit);
414
415  __ incq(rax);
416  __ Integer64PlusConstantToSmi(rcx, rcx, y);
417  __ cmpq(rcx, r8);
418  __ j(not_equal, exit);
419}
420
421
422TEST(Integer64PlusConstantToSmi) {
423  i::V8::Initialize(NULL);
424  // Allocate an executable page of memory.
425  size_t actual_size;
426  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
427                                                 &actual_size,
428                                                 true));
429  CHECK(buffer);
430  Isolate* isolate = CcTest::i_isolate();
431  HandleScope handles(isolate);
432  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
433
434  MacroAssembler* masm = &assembler;
435  EntryCode(masm);
436  Label exit;
437
438  int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2;
439
440  TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0);
441  TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1);
442  TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0);
443  TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5);
444  TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5);
445  TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue);
446  TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue);
447  TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue);
448  TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue);
449  TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0);
450  TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0);
451  TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue);
452
453  __ xor_(rax, rax);  // Success.
454  __ bind(&exit);
455  ExitCode(masm);
456  __ ret(0);
457
458  CodeDesc desc;
459  masm->GetCode(&desc);
460  // Call the function from C++.
461  int result = FUNCTION_CAST<F0>(buffer)();
462  CHECK_EQ(0, result);
463}
464
465
466TEST(SmiCheck) {
467  i::V8::Initialize(NULL);
468  // Allocate an executable page of memory.
469  size_t actual_size;
470  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
471                                                   &actual_size,
472                                                   true));
473  CHECK(buffer);
474  Isolate* isolate = CcTest::i_isolate();
475  HandleScope handles(isolate);
476  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
477
478  MacroAssembler* masm = &assembler;
479  EntryCode(masm);
480  Label exit;
481  Condition cond;
482
483  __ movl(rax, Immediate(1));  // Test number.
484
485  // CheckSmi
486
487  __ movl(rcx, Immediate(0));
488  __ Integer32ToSmi(rcx, rcx);
489  cond = masm->CheckSmi(rcx);
490  __ j(NegateCondition(cond), &exit);
491
492  __ incq(rax);
493  __ xor_(rcx, Immediate(kSmiTagMask));
494  cond = masm->CheckSmi(rcx);
495  __ j(cond, &exit);
496
497  __ incq(rax);
498  __ movl(rcx, Immediate(-1));
499  __ Integer32ToSmi(rcx, rcx);
500  cond = masm->CheckSmi(rcx);
501  __ j(NegateCondition(cond), &exit);
502
503  __ incq(rax);
504  __ xor_(rcx, Immediate(kSmiTagMask));
505  cond = masm->CheckSmi(rcx);
506  __ j(cond, &exit);
507
508  __ incq(rax);
509  __ movl(rcx, Immediate(Smi::kMaxValue));
510  __ Integer32ToSmi(rcx, rcx);
511  cond = masm->CheckSmi(rcx);
512  __ j(NegateCondition(cond), &exit);
513
514  __ incq(rax);
515  __ xor_(rcx, Immediate(kSmiTagMask));
516  cond = masm->CheckSmi(rcx);
517  __ j(cond, &exit);
518
519  __ incq(rax);
520  __ movl(rcx, Immediate(Smi::kMinValue));
521  __ Integer32ToSmi(rcx, rcx);
522  cond = masm->CheckSmi(rcx);
523  __ j(NegateCondition(cond), &exit);
524
525  __ incq(rax);
526  __ xor_(rcx, Immediate(kSmiTagMask));
527  cond = masm->CheckSmi(rcx);
528  __ j(cond, &exit);
529
530  // CheckPositiveSmi
531
532  __ incq(rax);
533  __ movl(rcx, Immediate(0));
534  __ Integer32ToSmi(rcx, rcx);
535  cond = masm->CheckNonNegativeSmi(rcx);
536  __ j(NegateCondition(cond), &exit);
537
538  __ incq(rax);
539  __ xor_(rcx, Immediate(kSmiTagMask));
540  cond = masm->CheckNonNegativeSmi(rcx);  // "zero" non-smi.
541  __ j(cond, &exit);
542
543  __ incq(rax);
544  __ movq(rcx, Immediate(-1));
545  __ Integer32ToSmi(rcx, rcx);
546  cond = masm->CheckNonNegativeSmi(rcx);  // Negative smis are not positive.
547  __ j(cond, &exit);
548
549  __ incq(rax);
550  __ movq(rcx, Immediate(Smi::kMinValue));
551  __ Integer32ToSmi(rcx, rcx);
552  cond = masm->CheckNonNegativeSmi(rcx);  // Most negative smi is not positive.
553  __ j(cond, &exit);
554
555  __ incq(rax);
556  __ xor_(rcx, Immediate(kSmiTagMask));
557  cond = masm->CheckNonNegativeSmi(rcx);  // "Negative" non-smi.
558  __ j(cond, &exit);
559
560  __ incq(rax);
561  __ movq(rcx, Immediate(Smi::kMaxValue));
562  __ Integer32ToSmi(rcx, rcx);
563  cond = masm->CheckNonNegativeSmi(rcx);  // Most positive smi is positive.
564  __ j(NegateCondition(cond), &exit);
565
566  __ incq(rax);
567  __ xor_(rcx, Immediate(kSmiTagMask));
568  cond = masm->CheckNonNegativeSmi(rcx);  // "Positive" non-smi.
569  __ j(cond, &exit);
570
571  // CheckIsMinSmi
572
573  __ incq(rax);
574  __ movq(rcx, Immediate(Smi::kMaxValue));
575  __ Integer32ToSmi(rcx, rcx);
576  cond = masm->CheckIsMinSmi(rcx);
577  __ j(cond, &exit);
578
579  __ incq(rax);
580  __ movq(rcx, Immediate(0));
581  __ Integer32ToSmi(rcx, rcx);
582  cond = masm->CheckIsMinSmi(rcx);
583  __ j(cond, &exit);
584
585  __ incq(rax);
586  __ movq(rcx, Immediate(Smi::kMinValue));
587  __ Integer32ToSmi(rcx, rcx);
588  cond = masm->CheckIsMinSmi(rcx);
589  __ j(NegateCondition(cond), &exit);
590
591  __ incq(rax);
592  __ movq(rcx, Immediate(Smi::kMinValue + 1));
593  __ Integer32ToSmi(rcx, rcx);
594  cond = masm->CheckIsMinSmi(rcx);
595  __ j(cond, &exit);
596
597  // CheckBothSmi
598
599  __ incq(rax);
600  __ movq(rcx, Immediate(Smi::kMaxValue));
601  __ Integer32ToSmi(rcx, rcx);
602  __ movq(rdx, Immediate(Smi::kMinValue));
603  __ Integer32ToSmi(rdx, rdx);
604  cond = masm->CheckBothSmi(rcx, rdx);
605  __ j(NegateCondition(cond), &exit);
606
607  __ incq(rax);
608  __ xor_(rcx, Immediate(kSmiTagMask));
609  cond = masm->CheckBothSmi(rcx, rdx);
610  __ j(cond, &exit);
611
612  __ incq(rax);
613  __ xor_(rdx, Immediate(kSmiTagMask));
614  cond = masm->CheckBothSmi(rcx, rdx);
615  __ j(cond, &exit);
616
617  __ incq(rax);
618  __ xor_(rcx, Immediate(kSmiTagMask));
619  cond = masm->CheckBothSmi(rcx, rdx);
620  __ j(cond, &exit);
621
622  __ incq(rax);
623  cond = masm->CheckBothSmi(rcx, rcx);
624  __ j(NegateCondition(cond), &exit);
625
626  __ incq(rax);
627  cond = masm->CheckBothSmi(rdx, rdx);
628  __ j(cond, &exit);
629
630  // CheckInteger32ValidSmiValue
631  __ incq(rax);
632  __ movq(rcx, Immediate(0));
633  cond = masm->CheckInteger32ValidSmiValue(rax);
634  __ j(NegateCondition(cond), &exit);
635
636  __ incq(rax);
637  __ movq(rcx, Immediate(-1));
638  cond = masm->CheckInteger32ValidSmiValue(rax);
639  __ j(NegateCondition(cond), &exit);
640
641  __ incq(rax);
642  __ movq(rcx, Immediate(Smi::kMaxValue));
643  cond = masm->CheckInteger32ValidSmiValue(rax);
644  __ j(NegateCondition(cond), &exit);
645
646  __ incq(rax);
647  __ movq(rcx, Immediate(Smi::kMinValue));
648  cond = masm->CheckInteger32ValidSmiValue(rax);
649  __ j(NegateCondition(cond), &exit);
650
651  // Success
652  __ xor_(rax, rax);
653
654  __ bind(&exit);
655  ExitCode(masm);
656  __ ret(0);
657
658  CodeDesc desc;
659  masm->GetCode(&desc);
660  // Call the function from C++.
661  int result = FUNCTION_CAST<F0>(buffer)();
662  CHECK_EQ(0, result);
663}
664
665
666
667void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
668  __ Move(rcx, Smi::FromInt(x));
669  __ movq(r11, rcx);
670  if (x == Smi::kMinValue || x == 0) {
671    // Negation fails.
672    __ movl(rax, Immediate(id + 8));
673    __ SmiNeg(r9, rcx, exit);
674
675    __ incq(rax);
676    __ cmpq(r11, rcx);
677    __ j(not_equal, exit);
678
679    __ incq(rax);
680    __ SmiNeg(rcx, rcx, exit);
681
682    __ incq(rax);
683    __ cmpq(r11, rcx);
684    __ j(not_equal, exit);
685  } else {
686    Label smi_ok, smi_ok2;
687    int result = -x;
688    __ movl(rax, Immediate(id));
689    __ Move(r8, Smi::FromInt(result));
690
691    __ SmiNeg(r9, rcx, &smi_ok);
692    __ jmp(exit);
693    __ bind(&smi_ok);
694    __ incq(rax);
695    __ cmpq(r9, r8);
696    __ j(not_equal, exit);
697
698    __ incq(rax);
699    __ cmpq(r11, rcx);
700    __ j(not_equal, exit);
701
702    __ incq(rax);
703    __ SmiNeg(rcx, rcx, &smi_ok2);
704    __ jmp(exit);
705    __ bind(&smi_ok2);
706    __ incq(rax);
707    __ cmpq(rcx, r8);
708    __ j(not_equal, exit);
709  }
710}
711
712
713TEST(SmiNeg) {
714  i::V8::Initialize(NULL);
715  // Allocate an executable page of memory.
716  size_t actual_size;
717  byte* buffer =
718      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
719                                      &actual_size,
720                                      true));
721  CHECK(buffer);
722  Isolate* isolate = CcTest::i_isolate();
723  HandleScope handles(isolate);
724  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
725
726  MacroAssembler* masm = &assembler;
727  EntryCode(masm);
728  Label exit;
729
730  TestSmiNeg(masm, &exit, 0x10, 0);
731  TestSmiNeg(masm, &exit, 0x20, 1);
732  TestSmiNeg(masm, &exit, 0x30, -1);
733  TestSmiNeg(masm, &exit, 0x40, 127);
734  TestSmiNeg(masm, &exit, 0x50, 65535);
735  TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue);
736  TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue);
737  TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue);
738
739  __ xor_(rax, rax);  // Success.
740  __ bind(&exit);
741  ExitCode(masm);
742  __ ret(0);
743
744  CodeDesc desc;
745  masm->GetCode(&desc);
746  // Call the function from C++.
747  int result = FUNCTION_CAST<F0>(buffer)();
748  CHECK_EQ(0, result);
749}
750
751
752static void SmiAddTest(MacroAssembler* masm,
753                       Label* exit,
754                       int id,
755                       int first,
756                       int second) {
757  __ movl(rcx, Immediate(first));
758  __ Integer32ToSmi(rcx, rcx);
759  __ movl(rdx, Immediate(second));
760  __ Integer32ToSmi(rdx, rdx);
761  __ movl(r8, Immediate(first + second));
762  __ Integer32ToSmi(r8, r8);
763
764  __ movl(rax, Immediate(id));  // Test number.
765  __ SmiAdd(r9, rcx, rdx, exit);
766  __ cmpq(r9, r8);
767  __ j(not_equal, exit);
768
769  __ incq(rax);
770  __ SmiAdd(rcx, rcx, rdx, exit);
771  __ cmpq(rcx, r8);
772  __ j(not_equal, exit);
773
774  __ movl(rcx, Immediate(first));
775  __ Integer32ToSmi(rcx, rcx);
776
777  __ incq(rax);
778  __ SmiAddConstant(r9, rcx, Smi::FromInt(second));
779  __ cmpq(r9, r8);
780  __ j(not_equal, exit);
781
782  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second));
783  __ cmpq(rcx, r8);
784  __ j(not_equal, exit);
785
786  __ movl(rcx, Immediate(first));
787  __ Integer32ToSmi(rcx, rcx);
788
789  i::SmiOperationExecutionMode mode;
790  mode.Add(i::PRESERVE_SOURCE_REGISTER);
791  mode.Add(i::BAILOUT_ON_OVERFLOW);
792  __ incq(rax);
793  __ SmiAddConstant(r9, rcx, Smi::FromInt(second), mode, exit);
794  __ cmpq(r9, r8);
795  __ j(not_equal, exit);
796
797  __ incq(rax);
798  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
799  __ cmpq(rcx, r8);
800  __ j(not_equal, exit);
801
802  __ movl(rcx, Immediate(first));
803  __ Integer32ToSmi(rcx, rcx);
804
805  mode.RemoveAll();
806  mode.Add(i::PRESERVE_SOURCE_REGISTER);
807  mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
808  Label done;
809  __ incq(rax);
810  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
811  __ jmp(exit);
812  __ bind(&done);
813  __ cmpq(rcx, r8);
814  __ j(not_equal, exit);
815}
816
817
818static void SmiAddOverflowTest(MacroAssembler* masm,
819                               Label* exit,
820                               int id,
821                               int x) {
822  // Adds a Smi to x so that the addition overflows.
823  ASSERT(x != 0);  // Can't overflow by adding a Smi.
824  int y_max = (x > 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue - x - 1);
825  int y_min = (x > 0) ? (Smi::kMaxValue - x + 1) : (Smi::kMinValue + 0);
826
827  __ movl(rax, Immediate(id));
828  __ Move(rcx, Smi::FromInt(x));
829  __ movq(r11, rcx);  // Store original Smi value of x in r11.
830  __ Move(rdx, Smi::FromInt(y_min));
831  {
832    Label overflow_ok;
833    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
834    __ jmp(exit);
835    __ bind(&overflow_ok);
836    __ incq(rax);
837    __ cmpq(rcx, r11);
838    __ j(not_equal, exit);
839  }
840
841  {
842    Label overflow_ok;
843    __ incq(rax);
844    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
845    __ jmp(exit);
846    __ bind(&overflow_ok);
847    __ incq(rax);
848    __ cmpq(rcx, r11);
849    __ j(not_equal, exit);
850  }
851
852  i::SmiOperationExecutionMode mode;
853  mode.Add(i::PRESERVE_SOURCE_REGISTER);
854  mode.Add(i::BAILOUT_ON_OVERFLOW);
855  __ movq(rcx, r11);
856  {
857    Label overflow_ok;
858    __ incq(rax);
859    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
860    __ jmp(exit);
861    __ bind(&overflow_ok);
862    __ incq(rax);
863    __ cmpq(rcx, r11);
864    __ j(not_equal, exit);
865  }
866
867  {
868    Label overflow_ok;
869    __ incq(rax);
870    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
871    __ jmp(exit);
872    __ bind(&overflow_ok);
873    __ incq(rax);
874    __ cmpq(rcx, r11);
875    __ j(not_equal, exit);
876  }
877
878  __ Move(rdx, Smi::FromInt(y_max));
879
880  {
881    Label overflow_ok;
882    __ incq(rax);
883    __ SmiAdd(r9, rcx, rdx, &overflow_ok);
884    __ jmp(exit);
885    __ bind(&overflow_ok);
886    __ incq(rax);
887    __ cmpq(rcx, r11);
888    __ j(not_equal, exit);
889  }
890
891  {
892    Label overflow_ok;
893    __ incq(rax);
894    __ SmiAdd(rcx, rcx, rdx, &overflow_ok);
895    __ jmp(exit);
896    __ bind(&overflow_ok);
897    __ incq(rax);
898    __ cmpq(rcx, r11);
899    __ j(not_equal, exit);
900  }
901
902  __ movq(rcx, r11);
903  {
904    Label overflow_ok;
905    __ incq(rax);
906    __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
907    __ jmp(exit);
908    __ bind(&overflow_ok);
909    __ incq(rax);
910    __ cmpq(rcx, r11);
911    __ j(not_equal, exit);
912  }
913
914  mode.RemoveAll();
915  mode.Add(i::BAILOUT_ON_OVERFLOW);
916  {
917    Label overflow_ok;
918    __ incq(rax);
919    __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
920    __ jmp(exit);
921    __ bind(&overflow_ok);
922    __ incq(rax);
923    __ cmpq(rcx, r11);
924    __ j(equal, exit);
925  }
926}
927
928
929TEST(SmiAdd) {
930  i::V8::Initialize(NULL);
931  // Allocate an executable page of memory.
932  size_t actual_size;
933  byte* buffer =
934      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3,
935                                      &actual_size,
936                                      true));
937  CHECK(buffer);
938  Isolate* isolate = CcTest::i_isolate();
939  HandleScope handles(isolate);
940  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
941
942  MacroAssembler* masm = &assembler;
943  EntryCode(masm);
944  Label exit;
945
946  // No-overflow tests.
947  SmiAddTest(masm, &exit, 0x10, 1, 2);
948  SmiAddTest(masm, &exit, 0x20, 1, -2);
949  SmiAddTest(masm, &exit, 0x30, -1, 2);
950  SmiAddTest(masm, &exit, 0x40, -1, -2);
951  SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000);
952  SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5);
953  SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5);
954  SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue);
955
956  SmiAddOverflowTest(masm, &exit, 0x90, -1);
957  SmiAddOverflowTest(masm, &exit, 0xA0, 1);
958  SmiAddOverflowTest(masm, &exit, 0xB0, 1024);
959  SmiAddOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
960  SmiAddOverflowTest(masm, &exit, 0xD0, -2);
961  SmiAddOverflowTest(masm, &exit, 0xE0, -42000);
962  SmiAddOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
963
964  __ xor_(rax, rax);  // Success.
965  __ bind(&exit);
966  ExitCode(masm);
967  __ ret(0);
968
969  CodeDesc desc;
970  masm->GetCode(&desc);
971  // Call the function from C++.
972  int result = FUNCTION_CAST<F0>(buffer)();
973  CHECK_EQ(0, result);
974}
975
976
977static void SmiSubTest(MacroAssembler* masm,
978                      Label* exit,
979                      int id,
980                      int first,
981                      int second) {
982  __ Move(rcx, Smi::FromInt(first));
983  __ Move(rdx, Smi::FromInt(second));
984  __ Move(r8, Smi::FromInt(first - second));
985
986  __ movl(rax, Immediate(id));  // Test 0.
987  __ SmiSub(r9, rcx, rdx, exit);
988  __ cmpq(r9, r8);
989  __ j(not_equal, exit);
990
991  __ incq(rax);  // Test 1.
992  __ SmiSub(rcx, rcx, rdx, exit);
993  __ cmpq(rcx, r8);
994  __ j(not_equal, exit);
995
996  __ Move(rcx, Smi::FromInt(first));
997
998  __ incq(rax);  // Test 2.
999  __ SmiSubConstant(r9, rcx, Smi::FromInt(second));
1000  __ cmpq(r9, r8);
1001  __ j(not_equal, exit);
1002
1003  __ incq(rax);  // Test 3.
1004  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second));
1005  __ cmpq(rcx, r8);
1006  __ j(not_equal, exit);
1007
1008  i::SmiOperationExecutionMode mode;
1009  mode.Add(i::PRESERVE_SOURCE_REGISTER);
1010  mode.Add(i::BAILOUT_ON_OVERFLOW);
1011  __ Move(rcx, Smi::FromInt(first));
1012  __ incq(rax);  // Test 4.
1013  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, exit);
1014  __ cmpq(rcx, r8);
1015  __ j(not_equal, exit);
1016
1017  __ Move(rcx, Smi::FromInt(first));
1018  __ incq(rax);  // Test 5.
1019  __ SmiSubConstant(r9, rcx, Smi::FromInt(second), mode, exit);
1020  __ cmpq(r9, r8);
1021  __ j(not_equal, exit);
1022
1023  mode.RemoveAll();
1024  mode.Add(i::PRESERVE_SOURCE_REGISTER);
1025  mode.Add(i::BAILOUT_ON_NO_OVERFLOW);
1026  __ Move(rcx, Smi::FromInt(first));
1027  Label done;
1028  __ incq(rax);  // Test 6.
1029  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, &done);
1030  __ jmp(exit);
1031  __ bind(&done);
1032  __ cmpq(rcx, r8);
1033  __ j(not_equal, exit);
1034}
1035
1036
1037static void SmiSubOverflowTest(MacroAssembler* masm,
1038                               Label* exit,
1039                               int id,
1040                               int x) {
1041  // Subtracts a Smi from x so that the subtraction overflows.
1042  ASSERT(x != -1);  // Can't overflow by subtracting a Smi.
1043  int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0);
1044  int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x);
1045
1046  __ movl(rax, Immediate(id));
1047  __ Move(rcx, Smi::FromInt(x));
1048  __ movq(r11, rcx);  // Store original Smi value of x in r11.
1049  __ Move(rdx, Smi::FromInt(y_min));
1050  {
1051    Label overflow_ok;
1052    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1053    __ jmp(exit);
1054    __ bind(&overflow_ok);
1055    __ incq(rax);
1056    __ cmpq(rcx, r11);
1057    __ j(not_equal, exit);
1058  }
1059
1060  {
1061    Label overflow_ok;
1062    __ incq(rax);
1063    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1064    __ jmp(exit);
1065    __ bind(&overflow_ok);
1066    __ incq(rax);
1067    __ cmpq(rcx, r11);
1068    __ j(not_equal, exit);
1069  }
1070
1071  i::SmiOperationExecutionMode mode;
1072  mode.Add(i::PRESERVE_SOURCE_REGISTER);
1073  mode.Add(i::BAILOUT_ON_OVERFLOW);
1074
1075  __ movq(rcx, r11);
1076  {
1077    Label overflow_ok;
1078    __ incq(rax);
1079    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
1080    __ jmp(exit);
1081    __ bind(&overflow_ok);
1082    __ incq(rax);
1083    __ cmpq(rcx, r11);
1084    __ j(not_equal, exit);
1085  }
1086
1087  {
1088    Label overflow_ok;
1089    __ incq(rax);
1090    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok);
1091    __ jmp(exit);
1092    __ bind(&overflow_ok);
1093    __ incq(rax);
1094    __ cmpq(rcx, r11);
1095    __ j(not_equal, exit);
1096  }
1097
1098  __ Move(rdx, Smi::FromInt(y_max));
1099
1100  {
1101    Label overflow_ok;
1102    __ incq(rax);
1103    __ SmiSub(r9, rcx, rdx, &overflow_ok);
1104    __ jmp(exit);
1105    __ bind(&overflow_ok);
1106    __ incq(rax);
1107    __ cmpq(rcx, r11);
1108    __ j(not_equal, exit);
1109  }
1110
1111  {
1112    Label overflow_ok;
1113    __ incq(rax);
1114    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
1115    __ jmp(exit);
1116    __ bind(&overflow_ok);
1117    __ incq(rax);
1118    __ cmpq(rcx, r11);
1119    __ j(not_equal, exit);
1120  }
1121
1122  __ movq(rcx, r11);
1123  {
1124    Label overflow_ok;
1125    __ incq(rax);
1126    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
1127    __ jmp(exit);
1128    __ bind(&overflow_ok);
1129    __ incq(rax);
1130    __ cmpq(rcx, r11);
1131    __ j(not_equal, exit);
1132  }
1133
1134  mode.RemoveAll();
1135  mode.Add(i::BAILOUT_ON_OVERFLOW);
1136  __ movq(rcx, r11);
1137  {
1138    Label overflow_ok;
1139    __ incq(rax);
1140    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok);
1141    __ jmp(exit);
1142    __ bind(&overflow_ok);
1143    __ incq(rax);
1144    __ cmpq(rcx, r11);
1145    __ j(equal, exit);
1146  }
1147}
1148
1149
1150TEST(SmiSub) {
1151  i::V8::Initialize(NULL);
1152  // Allocate an executable page of memory.
1153  size_t actual_size;
1154  byte* buffer =
1155      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
1156                                      &actual_size,
1157                                      true));
1158  CHECK(buffer);
1159  Isolate* isolate = CcTest::i_isolate();
1160  HandleScope handles(isolate);
1161  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1162
1163  MacroAssembler* masm = &assembler;
1164  EntryCode(masm);
1165  Label exit;
1166
1167  SmiSubTest(masm, &exit, 0x10, 1, 2);
1168  SmiSubTest(masm, &exit, 0x20, 1, -2);
1169  SmiSubTest(masm, &exit, 0x30, -1, 2);
1170  SmiSubTest(masm, &exit, 0x40, -1, -2);
1171  SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000);
1172  SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5);
1173  SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5);
1174  SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue);
1175  SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue);
1176
1177  SmiSubOverflowTest(masm, &exit, 0xA0, 1);
1178  SmiSubOverflowTest(masm, &exit, 0xB0, 1024);
1179  SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
1180  SmiSubOverflowTest(masm, &exit, 0xD0, -2);
1181  SmiSubOverflowTest(masm, &exit, 0xE0, -42000);
1182  SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
1183  SmiSubOverflowTest(masm, &exit, 0x100, 0);
1184
1185  __ xor_(rax, rax);  // Success.
1186  __ bind(&exit);
1187  ExitCode(masm);
1188  __ ret(0);
1189
1190  CodeDesc desc;
1191  masm->GetCode(&desc);
1192  // Call the function from C++.
1193  int result = FUNCTION_CAST<F0>(buffer)();
1194  CHECK_EQ(0, result);
1195}
1196
1197
1198
1199void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1200  int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y);
1201  bool negative_zero = (result == 0) && (x < 0 || y < 0);
1202  __ Move(rcx, Smi::FromInt(x));
1203  __ movq(r11, rcx);
1204  __ Move(rdx, Smi::FromInt(y));
1205  if (Smi::IsValid(result) && !negative_zero) {
1206    __ movl(rax, Immediate(id));
1207    __ Move(r8, Smi::FromIntptr(result));
1208    __ SmiMul(r9, rcx, rdx, exit);
1209    __ incq(rax);
1210    __ cmpq(r11, rcx);
1211    __ j(not_equal, exit);
1212    __ incq(rax);
1213    __ cmpq(r9, r8);
1214    __ j(not_equal, exit);
1215
1216    __ incq(rax);
1217    __ SmiMul(rcx, rcx, rdx, exit);
1218    __ cmpq(rcx, r8);
1219    __ j(not_equal, exit);
1220  } else {
1221    __ movl(rax, Immediate(id + 8));
1222    Label overflow_ok, overflow_ok2;
1223    __ SmiMul(r9, rcx, rdx, &overflow_ok);
1224    __ jmp(exit);
1225    __ bind(&overflow_ok);
1226    __ incq(rax);
1227    __ cmpq(r11, rcx);
1228    __ j(not_equal, exit);
1229    __ incq(rax);
1230    __ SmiMul(rcx, rcx, rdx, &overflow_ok2);
1231    __ jmp(exit);
1232    __ bind(&overflow_ok2);
1233    // 31-bit version doesn't preserve rcx on failure.
1234    // __ incq(rax);
1235    // __ cmpq(r11, rcx);
1236    // __ j(not_equal, exit);
1237  }
1238}
1239
1240
1241TEST(SmiMul) {
1242  i::V8::Initialize(NULL);
1243  // Allocate an executable page of memory.
1244  size_t actual_size;
1245  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1246                                                 &actual_size,
1247                                                 true));
1248  CHECK(buffer);
1249  Isolate* isolate = CcTest::i_isolate();
1250  HandleScope handles(isolate);
1251  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1252
1253  MacroAssembler* masm = &assembler;
1254  EntryCode(masm);
1255  Label exit;
1256
1257  TestSmiMul(masm, &exit, 0x10, 0, 0);
1258  TestSmiMul(masm, &exit, 0x20, -1, 0);
1259  TestSmiMul(masm, &exit, 0x30, 0, -1);
1260  TestSmiMul(masm, &exit, 0x40, -1, -1);
1261  TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000);
1262  TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff);
1263  TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff);
1264  TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1);
1265  TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2);
1266  TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2);
1267  TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2);
1268  TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2);
1269  TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2);
1270  TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2);
1271
1272  __ xor_(rax, rax);  // Success.
1273  __ bind(&exit);
1274  ExitCode(masm);
1275  __ ret(0);
1276
1277  CodeDesc desc;
1278  masm->GetCode(&desc);
1279  // Call the function from C++.
1280  int result = FUNCTION_CAST<F0>(buffer)();
1281  CHECK_EQ(0, result);
1282}
1283
1284
1285void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1286  bool division_by_zero = (y == 0);
1287  bool negative_zero = (x == 0 && y < 0);
1288#if V8_TARGET_ARCH_X64
1289  bool overflow = (x == Smi::kMinValue && y < 0);  // Safe approx. used.
1290#else
1291  bool overflow = (x == Smi::kMinValue && y == -1);
1292#endif
1293  bool fraction = !division_by_zero && !overflow && (x % y != 0);
1294  __ Move(r11, Smi::FromInt(x));
1295  __ Move(r14, Smi::FromInt(y));
1296  if (!fraction && !overflow && !negative_zero && !division_by_zero) {
1297    // Division succeeds
1298    __ movq(rcx, r11);
1299    __ movq(r15, Immediate(id));
1300    int result = x / y;
1301    __ Move(r8, Smi::FromInt(result));
1302    __ SmiDiv(r9, rcx, r14, exit);
1303    // Might have destroyed rcx and r14.
1304    __ incq(r15);
1305    __ cmpq(r9, r8);
1306    __ j(not_equal, exit);
1307
1308    __ incq(r15);
1309    __ movq(rcx, r11);
1310    __ Move(r14, Smi::FromInt(y));
1311    __ cmpq(rcx, r11);
1312    __ j(not_equal, exit);
1313
1314    __ incq(r15);
1315    __ SmiDiv(rcx, rcx, r14, exit);
1316
1317    __ incq(r15);
1318    __ cmpq(rcx, r8);
1319    __ j(not_equal, exit);
1320  } else {
1321    // Division fails.
1322    __ movq(r15, Immediate(id + 8));
1323
1324    Label fail_ok, fail_ok2;
1325    __ movq(rcx, r11);
1326    __ SmiDiv(r9, rcx, r14, &fail_ok);
1327    __ jmp(exit);
1328    __ bind(&fail_ok);
1329
1330    __ incq(r15);
1331    __ cmpq(rcx, r11);
1332    __ j(not_equal, exit);
1333
1334    __ incq(r15);
1335    __ SmiDiv(rcx, rcx, r14, &fail_ok2);
1336    __ jmp(exit);
1337    __ bind(&fail_ok2);
1338
1339    __ incq(r15);
1340    __ cmpq(rcx, r11);
1341    __ j(not_equal, exit);
1342  }
1343}
1344
1345
1346TEST(SmiDiv) {
1347  i::V8::Initialize(NULL);
1348  // Allocate an executable page of memory.
1349  size_t actual_size;
1350  byte* buffer =
1351      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1352                                      &actual_size,
1353                                      true));
1354  CHECK(buffer);
1355  Isolate* isolate = CcTest::i_isolate();
1356  HandleScope handles(isolate);
1357  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1358
1359  MacroAssembler* masm = &assembler;
1360  EntryCode(masm);
1361  Label exit;
1362
1363  __ push(r14);
1364  __ push(r15);
1365  TestSmiDiv(masm, &exit, 0x10, 1, 1);
1366  TestSmiDiv(masm, &exit, 0x20, 1, 0);
1367  TestSmiDiv(masm, &exit, 0x30, -1, 0);
1368  TestSmiDiv(masm, &exit, 0x40, 0, 1);
1369  TestSmiDiv(masm, &exit, 0x50, 0, -1);
1370  TestSmiDiv(masm, &exit, 0x60, 4, 2);
1371  TestSmiDiv(masm, &exit, 0x70, -4, 2);
1372  TestSmiDiv(masm, &exit, 0x80, 4, -2);
1373  TestSmiDiv(masm, &exit, 0x90, -4, -2);
1374  TestSmiDiv(masm, &exit, 0xa0, 3, 2);
1375  TestSmiDiv(masm, &exit, 0xb0, 3, 4);
1376  TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1377  TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1378  TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1379  TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1380  TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1381  TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1);
1382  TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1);
1383  TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1384  TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1);
1385
1386  __ xor_(r15, r15);  // Success.
1387  __ bind(&exit);
1388  __ movq(rax, r15);
1389  __ pop(r15);
1390  __ pop(r14);
1391  ExitCode(masm);
1392  __ ret(0);
1393
1394  CodeDesc desc;
1395  masm->GetCode(&desc);
1396  // Call the function from C++.
1397  int result = FUNCTION_CAST<F0>(buffer)();
1398  CHECK_EQ(0, result);
1399}
1400
1401
1402void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1403  bool division_by_zero = (y == 0);
1404  bool division_overflow = (x == Smi::kMinValue) && (y == -1);
1405  bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0);
1406  bool negative_zero = (!fraction && x < 0);
1407  __ Move(rcx, Smi::FromInt(x));
1408  __ movq(r11, rcx);
1409  __ Move(r14, Smi::FromInt(y));
1410  if (!division_overflow && !negative_zero && !division_by_zero) {
1411    // Modulo succeeds
1412    __ movq(r15, Immediate(id));
1413    int result = x % y;
1414    __ Move(r8, Smi::FromInt(result));
1415    __ SmiMod(r9, rcx, r14, exit);
1416
1417    __ incq(r15);
1418    __ cmpq(r9, r8);
1419    __ j(not_equal, exit);
1420
1421    __ incq(r15);
1422    __ cmpq(rcx, r11);
1423    __ j(not_equal, exit);
1424
1425    __ incq(r15);
1426    __ SmiMod(rcx, rcx, r14, exit);
1427
1428    __ incq(r15);
1429    __ cmpq(rcx, r8);
1430    __ j(not_equal, exit);
1431  } else {
1432    // Modulo fails.
1433    __ movq(r15, Immediate(id + 8));
1434
1435    Label fail_ok, fail_ok2;
1436    __ SmiMod(r9, rcx, r14, &fail_ok);
1437    __ jmp(exit);
1438    __ bind(&fail_ok);
1439
1440    __ incq(r15);
1441    __ cmpq(rcx, r11);
1442    __ j(not_equal, exit);
1443
1444    __ incq(r15);
1445    __ SmiMod(rcx, rcx, r14, &fail_ok2);
1446    __ jmp(exit);
1447    __ bind(&fail_ok2);
1448
1449    __ incq(r15);
1450    __ cmpq(rcx, r11);
1451    __ j(not_equal, exit);
1452  }
1453}
1454
1455
1456TEST(SmiMod) {
1457  i::V8::Initialize(NULL);
1458  // Allocate an executable page of memory.
1459  size_t actual_size;
1460  byte* buffer =
1461      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1462                                      &actual_size,
1463                                      true));
1464  CHECK(buffer);
1465  Isolate* isolate = CcTest::i_isolate();
1466  HandleScope handles(isolate);
1467  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1468
1469  MacroAssembler* masm = &assembler;
1470  EntryCode(masm);
1471  Label exit;
1472
1473  __ push(r14);
1474  __ push(r15);
1475  TestSmiMod(masm, &exit, 0x10, 1, 1);
1476  TestSmiMod(masm, &exit, 0x20, 1, 0);
1477  TestSmiMod(masm, &exit, 0x30, -1, 0);
1478  TestSmiMod(masm, &exit, 0x40, 0, 1);
1479  TestSmiMod(masm, &exit, 0x50, 0, -1);
1480  TestSmiMod(masm, &exit, 0x60, 4, 2);
1481  TestSmiMod(masm, &exit, 0x70, -4, 2);
1482  TestSmiMod(masm, &exit, 0x80, 4, -2);
1483  TestSmiMod(masm, &exit, 0x90, -4, -2);
1484  TestSmiMod(masm, &exit, 0xa0, 3, 2);
1485  TestSmiMod(masm, &exit, 0xb0, 3, 4);
1486  TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1487  TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1488  TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1489  TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1490  TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1491  TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1);
1492  TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1);
1493  TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1494  TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1);
1495
1496  __ xor_(r15, r15);  // Success.
1497  __ bind(&exit);
1498  __ movq(rax, r15);
1499  __ pop(r15);
1500  __ pop(r14);
1501  ExitCode(masm);
1502  __ ret(0);
1503
1504  CodeDesc desc;
1505  masm->GetCode(&desc);
1506  // Call the function from C++.
1507  int result = FUNCTION_CAST<F0>(buffer)();
1508  CHECK_EQ(0, result);
1509}
1510
1511
1512void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
1513  __ movl(rax, Immediate(id));
1514
1515  for (int i = 0; i < 8; i++) {
1516    __ Move(rcx, Smi::FromInt(x));
1517    SmiIndex index = masm->SmiToIndex(rdx, rcx, i);
1518    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1519    __ shl(index.reg, Immediate(index.scale));
1520    __ Set(r8, static_cast<intptr_t>(x) << i);
1521    __ cmpq(index.reg, r8);
1522    __ j(not_equal, exit);
1523    __ incq(rax);
1524    __ Move(rcx, Smi::FromInt(x));
1525    index = masm->SmiToIndex(rcx, rcx, i);
1526    ASSERT(index.reg.is(rcx));
1527    __ shl(rcx, Immediate(index.scale));
1528    __ Set(r8, static_cast<intptr_t>(x) << i);
1529    __ cmpq(rcx, r8);
1530    __ j(not_equal, exit);
1531    __ incq(rax);
1532
1533    __ Move(rcx, Smi::FromInt(x));
1534    index = masm->SmiToNegativeIndex(rdx, rcx, i);
1535    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1536    __ shl(index.reg, Immediate(index.scale));
1537    __ Set(r8, static_cast<intptr_t>(-x) << i);
1538    __ cmpq(index.reg, r8);
1539    __ j(not_equal, exit);
1540    __ incq(rax);
1541    __ Move(rcx, Smi::FromInt(x));
1542    index = masm->SmiToNegativeIndex(rcx, rcx, i);
1543    ASSERT(index.reg.is(rcx));
1544    __ shl(rcx, Immediate(index.scale));
1545    __ Set(r8, static_cast<intptr_t>(-x) << i);
1546    __ cmpq(rcx, r8);
1547    __ j(not_equal, exit);
1548    __ incq(rax);
1549  }
1550}
1551
1552
1553TEST(SmiIndex) {
1554  i::V8::Initialize(NULL);
1555  // Allocate an executable page of memory.
1556  size_t actual_size;
1557  byte* buffer =
1558      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
1559                                      &actual_size,
1560                                      true));
1561  CHECK(buffer);
1562  Isolate* isolate = CcTest::i_isolate();
1563  HandleScope handles(isolate);
1564  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1565
1566  MacroAssembler* masm = &assembler;
1567  EntryCode(masm);
1568  Label exit;
1569
1570  TestSmiIndex(masm, &exit, 0x10, 0);
1571  TestSmiIndex(masm, &exit, 0x20, 1);
1572  TestSmiIndex(masm, &exit, 0x30, 100);
1573  TestSmiIndex(masm, &exit, 0x40, 1000);
1574  TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue);
1575
1576  __ xor_(rax, rax);  // Success.
1577  __ bind(&exit);
1578  ExitCode(masm);
1579  __ ret(0);
1580
1581  CodeDesc desc;
1582  masm->GetCode(&desc);
1583  // Call the function from C++.
1584  int result = FUNCTION_CAST<F0>(buffer)();
1585  CHECK_EQ(0, result);
1586}
1587
1588
1589void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1590  __ movl(rax, Immediate(id));
1591  __ Move(rcx, Smi::FromInt(x));
1592  __ Move(rdx, Smi::FromInt(y));
1593  __ xor_(rdx, Immediate(kSmiTagMask));
1594  __ SelectNonSmi(r9, rcx, rdx, exit);
1595
1596  __ incq(rax);
1597  __ cmpq(r9, rdx);
1598  __ j(not_equal, exit);
1599
1600  __ incq(rax);
1601  __ Move(rcx, Smi::FromInt(x));
1602  __ Move(rdx, Smi::FromInt(y));
1603  __ xor_(rcx, Immediate(kSmiTagMask));
1604  __ SelectNonSmi(r9, rcx, rdx, exit);
1605
1606  __ incq(rax);
1607  __ cmpq(r9, rcx);
1608  __ j(not_equal, exit);
1609
1610  __ incq(rax);
1611  Label fail_ok;
1612  __ Move(rcx, Smi::FromInt(x));
1613  __ Move(rdx, Smi::FromInt(y));
1614  __ xor_(rcx, Immediate(kSmiTagMask));
1615  __ xor_(rdx, Immediate(kSmiTagMask));
1616  __ SelectNonSmi(r9, rcx, rdx, &fail_ok);
1617  __ jmp(exit);
1618  __ bind(&fail_ok);
1619}
1620
1621
1622TEST(SmiSelectNonSmi) {
1623  i::V8::Initialize(NULL);
1624  // Allocate an executable page of memory.
1625  size_t actual_size;
1626  byte* buffer =
1627      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1628                                      &actual_size,
1629                                      true));
1630  CHECK(buffer);
1631  Isolate* isolate = CcTest::i_isolate();
1632  HandleScope handles(isolate);
1633  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1634
1635  MacroAssembler* masm = &assembler;
1636  EntryCode(masm);
1637  Label exit;
1638
1639  TestSelectNonSmi(masm, &exit, 0x10, 0, 0);
1640  TestSelectNonSmi(masm, &exit, 0x20, 0, 1);
1641  TestSelectNonSmi(masm, &exit, 0x30, 1, 0);
1642  TestSelectNonSmi(masm, &exit, 0x40, 0, -1);
1643  TestSelectNonSmi(masm, &exit, 0x50, -1, 0);
1644  TestSelectNonSmi(masm, &exit, 0x60, -1, -1);
1645  TestSelectNonSmi(masm, &exit, 0x70, 1, 1);
1646  TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1647  TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1648
1649  __ xor_(rax, rax);  // Success.
1650  __ bind(&exit);
1651  ExitCode(masm);
1652  __ ret(0);
1653
1654  CodeDesc desc;
1655  masm->GetCode(&desc);
1656  // Call the function from C++.
1657  int result = FUNCTION_CAST<F0>(buffer)();
1658  CHECK_EQ(0, result);
1659}
1660
1661
1662void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1663  int result = x & y;
1664
1665  __ movl(rax, Immediate(id));
1666
1667  __ Move(rcx, Smi::FromInt(x));
1668  __ movq(r11, rcx);
1669  __ Move(rdx, Smi::FromInt(y));
1670  __ Move(r8, Smi::FromInt(result));
1671  __ SmiAnd(r9, rcx, rdx);
1672  __ cmpq(r8, r9);
1673  __ j(not_equal, exit);
1674
1675  __ incq(rax);
1676  __ cmpq(r11, rcx);
1677  __ j(not_equal, exit);
1678
1679  __ incq(rax);
1680  __ SmiAnd(rcx, rcx, rdx);
1681  __ cmpq(r8, rcx);
1682  __ j(not_equal, exit);
1683
1684  __ movq(rcx, r11);
1685  __ incq(rax);
1686  __ SmiAndConstant(r9, rcx, Smi::FromInt(y));
1687  __ cmpq(r8, r9);
1688  __ j(not_equal, exit);
1689
1690  __ incq(rax);
1691  __ cmpq(r11, rcx);
1692  __ j(not_equal, exit);
1693
1694  __ incq(rax);
1695  __ SmiAndConstant(rcx, rcx, Smi::FromInt(y));
1696  __ cmpq(r8, rcx);
1697  __ j(not_equal, exit);
1698}
1699
1700
1701TEST(SmiAnd) {
1702  i::V8::Initialize(NULL);
1703  // Allocate an executable page of memory.
1704  size_t actual_size;
1705  byte* buffer =
1706      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1707                                      &actual_size,
1708                                      true));
1709  CHECK(buffer);
1710  Isolate* isolate = CcTest::i_isolate();
1711  HandleScope handles(isolate);
1712  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1713
1714  MacroAssembler* masm = &assembler;
1715  EntryCode(masm);
1716  Label exit;
1717
1718  TestSmiAnd(masm, &exit, 0x10, 0, 0);
1719  TestSmiAnd(masm, &exit, 0x20, 0, 1);
1720  TestSmiAnd(masm, &exit, 0x30, 1, 0);
1721  TestSmiAnd(masm, &exit, 0x40, 0, -1);
1722  TestSmiAnd(masm, &exit, 0x50, -1, 0);
1723  TestSmiAnd(masm, &exit, 0x60, -1, -1);
1724  TestSmiAnd(masm, &exit, 0x70, 1, 1);
1725  TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1726  TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1727  TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1);
1728  TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1);
1729
1730  __ xor_(rax, rax);  // Success.
1731  __ bind(&exit);
1732  ExitCode(masm);
1733  __ ret(0);
1734
1735  CodeDesc desc;
1736  masm->GetCode(&desc);
1737  // Call the function from C++.
1738  int result = FUNCTION_CAST<F0>(buffer)();
1739  CHECK_EQ(0, result);
1740}
1741
1742
1743void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1744  int result = x | y;
1745
1746  __ movl(rax, Immediate(id));
1747
1748  __ Move(rcx, Smi::FromInt(x));
1749  __ movq(r11, rcx);
1750  __ Move(rdx, Smi::FromInt(y));
1751  __ Move(r8, Smi::FromInt(result));
1752  __ SmiOr(r9, rcx, rdx);
1753  __ cmpq(r8, r9);
1754  __ j(not_equal, exit);
1755
1756  __ incq(rax);
1757  __ cmpq(r11, rcx);
1758  __ j(not_equal, exit);
1759
1760  __ incq(rax);
1761  __ SmiOr(rcx, rcx, rdx);
1762  __ cmpq(r8, rcx);
1763  __ j(not_equal, exit);
1764
1765  __ movq(rcx, r11);
1766  __ incq(rax);
1767  __ SmiOrConstant(r9, rcx, Smi::FromInt(y));
1768  __ cmpq(r8, r9);
1769  __ j(not_equal, exit);
1770
1771  __ incq(rax);
1772  __ cmpq(r11, rcx);
1773  __ j(not_equal, exit);
1774
1775  __ incq(rax);
1776  __ SmiOrConstant(rcx, rcx, Smi::FromInt(y));
1777  __ cmpq(r8, rcx);
1778  __ j(not_equal, exit);
1779}
1780
1781
1782TEST(SmiOr) {
1783  i::V8::Initialize(NULL);
1784  // Allocate an executable page of memory.
1785  size_t actual_size;
1786  byte* buffer =
1787      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1788                                      &actual_size,
1789                                      true));
1790  CHECK(buffer);
1791  Isolate* isolate = CcTest::i_isolate();
1792  HandleScope handles(isolate);
1793  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1794
1795  MacroAssembler* masm = &assembler;
1796  EntryCode(masm);
1797  Label exit;
1798
1799  TestSmiOr(masm, &exit, 0x10, 0, 0);
1800  TestSmiOr(masm, &exit, 0x20, 0, 1);
1801  TestSmiOr(masm, &exit, 0x30, 1, 0);
1802  TestSmiOr(masm, &exit, 0x40, 0, -1);
1803  TestSmiOr(masm, &exit, 0x50, -1, 0);
1804  TestSmiOr(masm, &exit, 0x60, -1, -1);
1805  TestSmiOr(masm, &exit, 0x70, 1, 1);
1806  TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1807  TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1808  TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1);
1809  TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567);
1810  TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9);
1811  TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1);
1812
1813  __ xor_(rax, rax);  // Success.
1814  __ bind(&exit);
1815  ExitCode(masm);
1816  __ ret(0);
1817
1818  CodeDesc desc;
1819  masm->GetCode(&desc);
1820  // Call the function from C++.
1821  int result = FUNCTION_CAST<F0>(buffer)();
1822  CHECK_EQ(0, result);
1823}
1824
1825
1826void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1827  int result = x ^ y;
1828
1829  __ movl(rax, Immediate(id));
1830
1831  __ Move(rcx, Smi::FromInt(x));
1832  __ movq(r11, rcx);
1833  __ Move(rdx, Smi::FromInt(y));
1834  __ Move(r8, Smi::FromInt(result));
1835  __ SmiXor(r9, rcx, rdx);
1836  __ cmpq(r8, r9);
1837  __ j(not_equal, exit);
1838
1839  __ incq(rax);
1840  __ cmpq(r11, rcx);
1841  __ j(not_equal, exit);
1842
1843  __ incq(rax);
1844  __ SmiXor(rcx, rcx, rdx);
1845  __ cmpq(r8, rcx);
1846  __ j(not_equal, exit);
1847
1848  __ movq(rcx, r11);
1849  __ incq(rax);
1850  __ SmiXorConstant(r9, rcx, Smi::FromInt(y));
1851  __ cmpq(r8, r9);
1852  __ j(not_equal, exit);
1853
1854  __ incq(rax);
1855  __ cmpq(r11, rcx);
1856  __ j(not_equal, exit);
1857
1858  __ incq(rax);
1859  __ SmiXorConstant(rcx, rcx, Smi::FromInt(y));
1860  __ cmpq(r8, rcx);
1861  __ j(not_equal, exit);
1862}
1863
1864
1865TEST(SmiXor) {
1866  i::V8::Initialize(NULL);
1867  // Allocate an executable page of memory.
1868  size_t actual_size;
1869  byte* buffer =
1870      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1871                                      &actual_size,
1872                                      true));
1873  CHECK(buffer);
1874  Isolate* isolate = CcTest::i_isolate();
1875  HandleScope handles(isolate);
1876  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1877
1878  MacroAssembler* masm = &assembler;
1879  EntryCode(masm);
1880  Label exit;
1881
1882  TestSmiXor(masm, &exit, 0x10, 0, 0);
1883  TestSmiXor(masm, &exit, 0x20, 0, 1);
1884  TestSmiXor(masm, &exit, 0x30, 1, 0);
1885  TestSmiXor(masm, &exit, 0x40, 0, -1);
1886  TestSmiXor(masm, &exit, 0x50, -1, 0);
1887  TestSmiXor(masm, &exit, 0x60, -1, -1);
1888  TestSmiXor(masm, &exit, 0x70, 1, 1);
1889  TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1890  TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1891  TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1);
1892  TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567);
1893  TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9);
1894  TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1);
1895
1896  __ xor_(rax, rax);  // Success.
1897  __ bind(&exit);
1898  ExitCode(masm);
1899  __ ret(0);
1900
1901  CodeDesc desc;
1902  masm->GetCode(&desc);
1903  // Call the function from C++.
1904  int result = FUNCTION_CAST<F0>(buffer)();
1905  CHECK_EQ(0, result);
1906}
1907
1908
1909void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) {
1910  int result = ~x;
1911  __ movl(rax, Immediate(id));
1912
1913  __ Move(r8, Smi::FromInt(result));
1914  __ Move(rcx, Smi::FromInt(x));
1915  __ movq(r11, rcx);
1916
1917  __ SmiNot(r9, rcx);
1918  __ cmpq(r9, r8);
1919  __ j(not_equal, exit);
1920
1921  __ incq(rax);
1922  __ cmpq(r11, rcx);
1923  __ j(not_equal, exit);
1924
1925  __ incq(rax);
1926  __ SmiNot(rcx, rcx);
1927  __ cmpq(rcx, r8);
1928  __ j(not_equal, exit);
1929}
1930
1931
1932TEST(SmiNot) {
1933  i::V8::Initialize(NULL);
1934  // Allocate an executable page of memory.
1935  size_t actual_size;
1936  byte* buffer =
1937      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1938                                      &actual_size,
1939                                      true));
1940  CHECK(buffer);
1941  Isolate* isolate = CcTest::i_isolate();
1942  HandleScope handles(isolate);
1943  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
1944
1945  MacroAssembler* masm = &assembler;
1946  EntryCode(masm);
1947  Label exit;
1948
1949  TestSmiNot(masm, &exit, 0x10, 0);
1950  TestSmiNot(masm, &exit, 0x20, 1);
1951  TestSmiNot(masm, &exit, 0x30, -1);
1952  TestSmiNot(masm, &exit, 0x40, 127);
1953  TestSmiNot(masm, &exit, 0x50, 65535);
1954  TestSmiNot(masm, &exit, 0x60, Smi::kMinValue);
1955  TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue);
1956  TestSmiNot(masm, &exit, 0x80, 0x05555555);
1957
1958  __ xor_(rax, rax);  // Success.
1959  __ bind(&exit);
1960  ExitCode(masm);
1961  __ ret(0);
1962
1963  CodeDesc desc;
1964  masm->GetCode(&desc);
1965  // Call the function from C++.
1966  int result = FUNCTION_CAST<F0>(buffer)();
1967  CHECK_EQ(0, result);
1968}
1969
1970
1971void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
1972  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1973  const int kNumShifts = 5;
1974  __ movl(rax, Immediate(id));
1975  for (int i = 0; i < kNumShifts; i++) {
1976    // rax == id + i * 10.
1977    int shift = shifts[i];
1978    int result = x << shift;
1979    CHECK(Smi::IsValid(result));
1980    __ Move(r8, Smi::FromInt(result));
1981    __ Move(rcx, Smi::FromInt(x));
1982    __ SmiShiftLeftConstant(r9, rcx, shift);
1983
1984    __ incq(rax);
1985    __ cmpq(r9, r8);
1986    __ j(not_equal, exit);
1987
1988    __ incq(rax);
1989    __ Move(rcx, Smi::FromInt(x));
1990    __ SmiShiftLeftConstant(rcx, rcx, shift);
1991
1992    __ incq(rax);
1993    __ cmpq(rcx, r8);
1994    __ j(not_equal, exit);
1995
1996    __ incq(rax);
1997    __ Move(rdx, Smi::FromInt(x));
1998    __ Move(rcx, Smi::FromInt(shift));
1999    __ SmiShiftLeft(r9, rdx, rcx);
2000
2001    __ incq(rax);
2002    __ cmpq(r9, r8);
2003    __ j(not_equal, exit);
2004
2005    __ incq(rax);
2006    __ Move(rdx, Smi::FromInt(x));
2007    __ Move(r11, Smi::FromInt(shift));
2008    __ SmiShiftLeft(r9, rdx, r11);
2009
2010    __ incq(rax);
2011    __ cmpq(r9, r8);
2012    __ j(not_equal, exit);
2013
2014    __ incq(rax);
2015    __ Move(rdx, Smi::FromInt(x));
2016    __ Move(r11, Smi::FromInt(shift));
2017    __ SmiShiftLeft(rdx, rdx, r11);
2018
2019    __ incq(rax);
2020    __ cmpq(rdx, r8);
2021    __ j(not_equal, exit);
2022
2023    __ incq(rax);
2024  }
2025}
2026
2027
2028TEST(SmiShiftLeft) {
2029  i::V8::Initialize(NULL);
2030  // Allocate an executable page of memory.
2031  size_t actual_size;
2032  byte* buffer =
2033      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 7,
2034                                      &actual_size,
2035                                      true));
2036  CHECK(buffer);
2037  Isolate* isolate = CcTest::i_isolate();
2038  HandleScope handles(isolate);
2039  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2040
2041  MacroAssembler* masm = &assembler;
2042  EntryCode(masm);
2043  Label exit;
2044
2045  TestSmiShiftLeft(masm, &exit, 0x10, 0);
2046  TestSmiShiftLeft(masm, &exit, 0x50, 1);
2047  TestSmiShiftLeft(masm, &exit, 0x90, 127);
2048  TestSmiShiftLeft(masm, &exit, 0xD0, 65535);
2049  TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue);
2050  TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue);
2051  TestSmiShiftLeft(masm, &exit, 0x190, -1);
2052
2053  __ xor_(rax, rax);  // Success.
2054  __ bind(&exit);
2055  ExitCode(masm);
2056  __ ret(0);
2057
2058  CodeDesc desc;
2059  masm->GetCode(&desc);
2060  // Call the function from C++.
2061  int result = FUNCTION_CAST<F0>(buffer)();
2062  CHECK_EQ(0, result);
2063}
2064
2065
2066void TestSmiShiftLogicalRight(MacroAssembler* masm,
2067                              Label* exit,
2068                              int id,
2069                              int x) {
2070  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2071  const int kNumShifts = 5;
2072  __ movl(rax, Immediate(id));
2073  for (int i = 0; i < kNumShifts; i++) {
2074    int shift = shifts[i];
2075    intptr_t result = static_cast<unsigned int>(x) >> shift;
2076    if (Smi::IsValid(result)) {
2077      __ Move(r8, Smi::FromInt(static_cast<int>(result)));
2078      __ Move(rcx, Smi::FromInt(x));
2079      __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit);
2080
2081      __ incq(rax);
2082      __ cmpq(r9, r8);
2083      __ j(not_equal, exit);
2084
2085      __ incq(rax);
2086      __ Move(rdx, Smi::FromInt(x));
2087      __ Move(rcx, Smi::FromInt(shift));
2088      __ SmiShiftLogicalRight(r9, rdx, rcx, exit);
2089
2090      __ incq(rax);
2091      __ cmpq(r9, r8);
2092      __ j(not_equal, exit);
2093
2094      __ incq(rax);
2095      __ Move(rdx, Smi::FromInt(x));
2096      __ Move(r11, Smi::FromInt(shift));
2097      __ SmiShiftLogicalRight(r9, rdx, r11, exit);
2098
2099      __ incq(rax);
2100      __ cmpq(r9, r8);
2101      __ j(not_equal, exit);
2102
2103      __ incq(rax);
2104    } else {
2105      // Cannot happen with long smis.
2106      Label fail_ok;
2107      __ Move(rcx, Smi::FromInt(x));
2108      __ movq(r11, rcx);
2109      __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok);
2110      __ jmp(exit);
2111      __ bind(&fail_ok);
2112
2113      __ incq(rax);
2114      __ cmpq(rcx, r11);
2115      __ j(not_equal, exit);
2116
2117      __ incq(rax);
2118      __ Move(r8, Smi::FromInt(shift));
2119      Label fail_ok3;
2120      __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3);
2121      __ jmp(exit);
2122      __ bind(&fail_ok3);
2123
2124      __ incq(rax);
2125      __ cmpq(rcx, r11);
2126      __ j(not_equal, exit);
2127
2128      __ addq(rax, Immediate(3));
2129    }
2130  }
2131}
2132
2133
2134TEST(SmiShiftLogicalRight) {
2135  i::V8::Initialize(NULL);
2136  // Allocate an executable page of memory.
2137  size_t actual_size;
2138  byte* buffer =
2139      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 5,
2140                                      &actual_size,
2141                                      true));
2142  CHECK(buffer);
2143  Isolate* isolate = CcTest::i_isolate();
2144  HandleScope handles(isolate);
2145  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2146
2147  MacroAssembler* masm = &assembler;
2148  EntryCode(masm);
2149  Label exit;
2150
2151  TestSmiShiftLogicalRight(masm, &exit, 0x10, 0);
2152  TestSmiShiftLogicalRight(masm, &exit, 0x30, 1);
2153  TestSmiShiftLogicalRight(masm, &exit, 0x50, 127);
2154  TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535);
2155  TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue);
2156  TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue);
2157  TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1);
2158
2159  __ xor_(rax, rax);  // Success.
2160  __ bind(&exit);
2161  ExitCode(masm);
2162  __ ret(0);
2163
2164  CodeDesc desc;
2165  masm->GetCode(&desc);
2166  // Call the function from C++.
2167  int result = FUNCTION_CAST<F0>(buffer)();
2168  CHECK_EQ(0, result);
2169}
2170
2171
2172void TestSmiShiftArithmeticRight(MacroAssembler* masm,
2173                                 Label* exit,
2174                                 int id,
2175                                 int x) {
2176  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
2177  const int kNumShifts = 5;
2178  __ movl(rax, Immediate(id));
2179  for (int i = 0; i < kNumShifts; i++) {
2180    int shift = shifts[i];
2181    // Guaranteed arithmetic shift.
2182    int result = (x < 0) ? ~((~x) >> shift) : (x >> shift);
2183    __ Move(r8, Smi::FromInt(result));
2184    __ Move(rcx, Smi::FromInt(x));
2185    __ SmiShiftArithmeticRightConstant(rcx, rcx, shift);
2186
2187    __ cmpq(rcx, r8);
2188    __ j(not_equal, exit);
2189
2190    __ incq(rax);
2191    __ Move(rdx, Smi::FromInt(x));
2192    __ Move(r11, Smi::FromInt(shift));
2193    __ SmiShiftArithmeticRight(rdx, rdx, r11);
2194
2195    __ cmpq(rdx, r8);
2196    __ j(not_equal, exit);
2197
2198    __ incq(rax);
2199  }
2200}
2201
2202
2203TEST(SmiShiftArithmeticRight) {
2204  i::V8::Initialize(NULL);
2205  // Allocate an executable page of memory.
2206  size_t actual_size;
2207  byte* buffer =
2208      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3,
2209                                      &actual_size,
2210                                      true));
2211  CHECK(buffer);
2212  Isolate* isolate = CcTest::i_isolate();
2213  HandleScope handles(isolate);
2214  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2215
2216  MacroAssembler* masm = &assembler;
2217  EntryCode(masm);
2218  Label exit;
2219
2220  TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0);
2221  TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1);
2222  TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127);
2223  TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535);
2224  TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue);
2225  TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue);
2226  TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1);
2227
2228  __ xor_(rax, rax);  // Success.
2229  __ bind(&exit);
2230  ExitCode(masm);
2231  __ ret(0);
2232
2233  CodeDesc desc;
2234  masm->GetCode(&desc);
2235  // Call the function from C++.
2236  int result = FUNCTION_CAST<F0>(buffer)();
2237  CHECK_EQ(0, result);
2238}
2239
2240
2241void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
2242  ASSERT(x >= 0);
2243  int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 };
2244  int power_count = 8;
2245  __ movl(rax, Immediate(id));
2246  for (int i = 0; i  < power_count; i++) {
2247    int power = powers[i];
2248    intptr_t result = static_cast<intptr_t>(x) << power;
2249    __ Set(r8, result);
2250    __ Move(rcx, Smi::FromInt(x));
2251    __ movq(r11, rcx);
2252    __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power);
2253    __ cmpq(rdx, r8);
2254    __ j(not_equal, exit);
2255    __ incq(rax);
2256    __ cmpq(r11, rcx);  // rcx unchanged.
2257    __ j(not_equal, exit);
2258    __ incq(rax);
2259    __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power);
2260    __ cmpq(rdx, r8);
2261    __ j(not_equal, exit);
2262    __ incq(rax);
2263  }
2264}
2265
2266
2267TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
2268  i::V8::Initialize(NULL);
2269  // Allocate an executable page of memory.
2270  size_t actual_size;
2271  byte* buffer =
2272      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4,
2273                                      &actual_size,
2274                                      true));
2275  CHECK(buffer);
2276  Isolate* isolate = CcTest::i_isolate();
2277  HandleScope handles(isolate);
2278  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2279
2280  MacroAssembler* masm = &assembler;
2281  EntryCode(masm);
2282  Label exit;
2283
2284  TestPositiveSmiPowerUp(masm, &exit, 0x20, 0);
2285  TestPositiveSmiPowerUp(masm, &exit, 0x40, 1);
2286  TestPositiveSmiPowerUp(masm, &exit, 0x60, 127);
2287  TestPositiveSmiPowerUp(masm, &exit, 0x80, 128);
2288  TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255);
2289  TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256);
2290  TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535);
2291  TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536);
2292  TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue);
2293
2294  __ xor_(rax, rax);  // Success.
2295  __ bind(&exit);
2296  ExitCode(masm);
2297  __ ret(0);
2298
2299  CodeDesc desc;
2300  masm->GetCode(&desc);
2301  // Call the function from C++.
2302  int result = FUNCTION_CAST<F0>(buffer)();
2303  CHECK_EQ(0, result);
2304}
2305
2306
2307TEST(OperandOffset) {
2308  i::V8::Initialize(NULL);
2309  uint32_t data[256];
2310  for (uint32_t i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
2311
2312  // Allocate an executable page of memory.
2313  size_t actual_size;
2314  byte* buffer =
2315      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
2316                                      &actual_size,
2317                                      true));
2318  CHECK(buffer);
2319  Isolate* isolate = CcTest::i_isolate();
2320  HandleScope handles(isolate);
2321  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2322
2323  MacroAssembler* masm = &assembler;
2324  Label exit;
2325
2326  EntryCode(masm);
2327  __ push(r13);
2328  __ push(r14);
2329  __ push(rbx);
2330  __ push(rbp);
2331  __ push(Immediate(0x100));  // <-- rbp
2332  __ movq(rbp, rsp);
2333  __ push(Immediate(0x101));
2334  __ push(Immediate(0x102));
2335  __ push(Immediate(0x103));
2336  __ push(Immediate(0x104));
2337  __ push(Immediate(0x105));  // <-- rbx
2338  __ push(Immediate(0x106));
2339  __ push(Immediate(0x107));
2340  __ push(Immediate(0x108));
2341  __ push(Immediate(0x109));  // <-- rsp
2342  // rbp = rsp[9]
2343  // r15 = rsp[3]
2344  // rbx = rsp[5]
2345  // r13 = rsp[7]
2346  __ lea(r14, Operand(rsp, 3 * kPointerSize));
2347  __ lea(r13, Operand(rbp, -3 * kPointerSize));
2348  __ lea(rbx, Operand(rbp, -5 * kPointerSize));
2349  __ movl(rcx, Immediate(2));
2350  __ movq(r8, reinterpret_cast<Address>(&data[128]), RelocInfo::NONE64);
2351  __ movl(rax, Immediate(1));
2352
2353  Operand sp0 = Operand(rsp, 0);
2354
2355  // Test 1.
2356  __ movl(rdx, sp0);  // Sanity check.
2357  __ cmpl(rdx, Immediate(0x109));
2358  __ j(not_equal, &exit);
2359  __ incq(rax);
2360
2361  // Test 2.
2362  // Zero to non-zero displacement.
2363  __ movl(rdx, Operand(sp0, 2 * kPointerSize));
2364  __ cmpl(rdx, Immediate(0x107));
2365  __ j(not_equal, &exit);
2366  __ incq(rax);
2367
2368  Operand sp2 = Operand(rsp, 2 * kPointerSize);
2369
2370  // Test 3.
2371  __ movl(rdx, sp2);  // Sanity check.
2372  __ cmpl(rdx, Immediate(0x107));
2373  __ j(not_equal, &exit);
2374  __ incq(rax);
2375
2376  __ movl(rdx, Operand(sp2, 2 * kPointerSize));
2377  __ cmpl(rdx, Immediate(0x105));
2378  __ j(not_equal, &exit);
2379  __ incq(rax);
2380
2381  // Non-zero to zero displacement.
2382  __ movl(rdx, Operand(sp2, -2 * kPointerSize));
2383  __ cmpl(rdx, Immediate(0x109));
2384  __ j(not_equal, &exit);
2385  __ incq(rax);
2386
2387  Operand sp2c2 = Operand(rsp, rcx, times_pointer_size, 2 * kPointerSize);
2388
2389  // Test 6.
2390  __ movl(rdx, sp2c2);  // Sanity check.
2391  __ cmpl(rdx, Immediate(0x105));
2392  __ j(not_equal, &exit);
2393  __ incq(rax);
2394
2395  __ movl(rdx, Operand(sp2c2, 2 * kPointerSize));
2396  __ cmpl(rdx, Immediate(0x103));
2397  __ j(not_equal, &exit);
2398  __ incq(rax);
2399
2400  // Non-zero to zero displacement.
2401  __ movl(rdx, Operand(sp2c2, -2 * kPointerSize));
2402  __ cmpl(rdx, Immediate(0x107));
2403  __ j(not_equal, &exit);
2404  __ incq(rax);
2405
2406
2407  Operand bp0 = Operand(rbp, 0);
2408
2409  // Test 9.
2410  __ movl(rdx, bp0);  // Sanity check.
2411  __ cmpl(rdx, Immediate(0x100));
2412  __ j(not_equal, &exit);
2413  __ incq(rax);
2414
2415  // Zero to non-zero displacement.
2416  __ movl(rdx, Operand(bp0, -2 * kPointerSize));
2417  __ cmpl(rdx, Immediate(0x102));
2418  __ j(not_equal, &exit);
2419  __ incq(rax);
2420
2421  Operand bp2 = Operand(rbp, -2 * kPointerSize);
2422
2423  // Test 11.
2424  __ movl(rdx, bp2);  // Sanity check.
2425  __ cmpl(rdx, Immediate(0x102));
2426  __ j(not_equal, &exit);
2427  __ incq(rax);
2428
2429  // Non-zero to zero displacement.
2430  __ movl(rdx, Operand(bp2, 2 * kPointerSize));
2431  __ cmpl(rdx, Immediate(0x100));
2432  __ j(not_equal, &exit);
2433  __ incq(rax);
2434
2435  __ movl(rdx, Operand(bp2, -2 * kPointerSize));
2436  __ cmpl(rdx, Immediate(0x104));
2437  __ j(not_equal, &exit);
2438  __ incq(rax);
2439
2440  Operand bp2c4 = Operand(rbp, rcx, times_pointer_size, -4 * kPointerSize);
2441
2442  // Test 14:
2443  __ movl(rdx, bp2c4);  // Sanity check.
2444  __ cmpl(rdx, Immediate(0x102));
2445  __ j(not_equal, &exit);
2446  __ incq(rax);
2447
2448  __ movl(rdx, Operand(bp2c4, 2 * kPointerSize));
2449  __ cmpl(rdx, Immediate(0x100));
2450  __ j(not_equal, &exit);
2451  __ incq(rax);
2452
2453  __ movl(rdx, Operand(bp2c4, -2 * kPointerSize));
2454  __ cmpl(rdx, Immediate(0x104));
2455  __ j(not_equal, &exit);
2456  __ incq(rax);
2457
2458  Operand bx0 = Operand(rbx, 0);
2459
2460  // Test 17.
2461  __ movl(rdx, bx0);  // Sanity check.
2462  __ cmpl(rdx, Immediate(0x105));
2463  __ j(not_equal, &exit);
2464  __ incq(rax);
2465
2466  __ movl(rdx, Operand(bx0, 5 * kPointerSize));
2467  __ cmpl(rdx, Immediate(0x100));
2468  __ j(not_equal, &exit);
2469  __ incq(rax);
2470
2471  __ movl(rdx, Operand(bx0, -4 * kPointerSize));
2472  __ cmpl(rdx, Immediate(0x109));
2473  __ j(not_equal, &exit);
2474  __ incq(rax);
2475
2476  Operand bx2 = Operand(rbx, 2 * kPointerSize);
2477
2478  // Test 20.
2479  __ movl(rdx, bx2);  // Sanity check.
2480  __ cmpl(rdx, Immediate(0x103));
2481  __ j(not_equal, &exit);
2482  __ incq(rax);
2483
2484  __ movl(rdx, Operand(bx2, 2 * kPointerSize));
2485  __ cmpl(rdx, Immediate(0x101));
2486  __ j(not_equal, &exit);
2487  __ incq(rax);
2488
2489  // Non-zero to zero displacement.
2490  __ movl(rdx, Operand(bx2, -2 * kPointerSize));
2491  __ cmpl(rdx, Immediate(0x105));
2492  __ j(not_equal, &exit);
2493  __ incq(rax);
2494
2495  Operand bx2c2 = Operand(rbx, rcx, times_pointer_size, -2 * kPointerSize);
2496
2497  // Test 23.
2498  __ movl(rdx, bx2c2);  // Sanity check.
2499  __ cmpl(rdx, Immediate(0x105));
2500  __ j(not_equal, &exit);
2501  __ incq(rax);
2502
2503  __ movl(rdx, Operand(bx2c2, 2 * kPointerSize));
2504  __ cmpl(rdx, Immediate(0x103));
2505  __ j(not_equal, &exit);
2506  __ incq(rax);
2507
2508  __ movl(rdx, Operand(bx2c2, -2 * kPointerSize));
2509  __ cmpl(rdx, Immediate(0x107));
2510  __ j(not_equal, &exit);
2511  __ incq(rax);
2512
2513  Operand r80 = Operand(r8, 0);
2514
2515  // Test 26.
2516  __ movl(rdx, r80);  // Sanity check.
2517  __ cmpl(rdx, Immediate(0x80808080));
2518  __ j(not_equal, &exit);
2519  __ incq(rax);
2520
2521  __ movl(rdx, Operand(r80, -8 * kIntSize));
2522  __ cmpl(rdx, Immediate(0x78787878));
2523  __ j(not_equal, &exit);
2524  __ incq(rax);
2525
2526  __ movl(rdx, Operand(r80, 8 * kIntSize));
2527  __ cmpl(rdx, Immediate(0x88888888));
2528  __ j(not_equal, &exit);
2529  __ incq(rax);
2530
2531  __ movl(rdx, Operand(r80, -64 * kIntSize));
2532  __ cmpl(rdx, Immediate(0x40404040));
2533  __ j(not_equal, &exit);
2534  __ incq(rax);
2535
2536  __ movl(rdx, Operand(r80, 64 * kIntSize));
2537  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2538  __ j(not_equal, &exit);
2539  __ incq(rax);
2540
2541  Operand r88 = Operand(r8, 8 * kIntSize);
2542
2543  // Test 31.
2544  __ movl(rdx, r88);  // Sanity check.
2545  __ cmpl(rdx, Immediate(0x88888888));
2546  __ j(not_equal, &exit);
2547  __ incq(rax);
2548
2549  __ movl(rdx, Operand(r88, -8 * kIntSize));
2550  __ cmpl(rdx, Immediate(0x80808080));
2551  __ j(not_equal, &exit);
2552  __ incq(rax);
2553
2554  __ movl(rdx, Operand(r88, 8 * kIntSize));
2555  __ cmpl(rdx, Immediate(0x90909090));
2556  __ j(not_equal, &exit);
2557  __ incq(rax);
2558
2559  __ movl(rdx, Operand(r88, -64 * kIntSize));
2560  __ cmpl(rdx, Immediate(0x48484848));
2561  __ j(not_equal, &exit);
2562  __ incq(rax);
2563
2564  __ movl(rdx, Operand(r88, 64 * kIntSize));
2565  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2566  __ j(not_equal, &exit);
2567  __ incq(rax);
2568
2569
2570  Operand r864 = Operand(r8, 64 * kIntSize);
2571
2572  // Test 36.
2573  __ movl(rdx, r864);  // Sanity check.
2574  __ cmpl(rdx, Immediate(0xC0C0C0C0));
2575  __ j(not_equal, &exit);
2576  __ incq(rax);
2577
2578  __ movl(rdx, Operand(r864, -8 * kIntSize));
2579  __ cmpl(rdx, Immediate(0xB8B8B8B8));
2580  __ j(not_equal, &exit);
2581  __ incq(rax);
2582
2583  __ movl(rdx, Operand(r864, 8 * kIntSize));
2584  __ cmpl(rdx, Immediate(0xC8C8C8C8));
2585  __ j(not_equal, &exit);
2586  __ incq(rax);
2587
2588  __ movl(rdx, Operand(r864, -64 * kIntSize));
2589  __ cmpl(rdx, Immediate(0x80808080));
2590  __ j(not_equal, &exit);
2591  __ incq(rax);
2592
2593  __ movl(rdx, Operand(r864, 32 * kIntSize));
2594  __ cmpl(rdx, Immediate(0xE0E0E0E0));
2595  __ j(not_equal, &exit);
2596  __ incq(rax);
2597
2598  // 32-bit offset to 8-bit offset.
2599  __ movl(rdx, Operand(r864, -60 * kIntSize));
2600  __ cmpl(rdx, Immediate(0x84848484));
2601  __ j(not_equal, &exit);
2602  __ incq(rax);
2603
2604  __ movl(rdx, Operand(r864, 60 * kIntSize));
2605  __ cmpl(rdx, Immediate(0xFCFCFCFC));
2606  __ j(not_equal, &exit);
2607  __ incq(rax);
2608
2609  // Test unaligned offsets.
2610
2611  // Test 43.
2612  __ movl(rdx, Operand(r80, 2));
2613  __ cmpl(rdx, Immediate(0x81818080));
2614  __ j(not_equal, &exit);
2615  __ incq(rax);
2616
2617  __ movl(rdx, Operand(r80, -2));
2618  __ cmpl(rdx, Immediate(0x80807F7F));
2619  __ j(not_equal, &exit);
2620  __ incq(rax);
2621
2622  __ movl(rdx, Operand(r80, 126));
2623  __ cmpl(rdx, Immediate(0xA0A09F9F));
2624  __ j(not_equal, &exit);
2625  __ incq(rax);
2626
2627  __ movl(rdx, Operand(r80, -126));
2628  __ cmpl(rdx, Immediate(0x61616060));
2629  __ j(not_equal, &exit);
2630  __ incq(rax);
2631
2632  __ movl(rdx, Operand(r80, 254));
2633  __ cmpl(rdx, Immediate(0xC0C0BFBF));
2634  __ j(not_equal, &exit);
2635  __ incq(rax);
2636
2637  __ movl(rdx, Operand(r80, -254));
2638  __ cmpl(rdx, Immediate(0x41414040));
2639  __ j(not_equal, &exit);
2640  __ incq(rax);
2641
2642  // Success.
2643
2644  __ movl(rax, Immediate(0));
2645  __ bind(&exit);
2646  __ lea(rsp, Operand(rbp, kPointerSize));
2647  __ pop(rbp);
2648  __ pop(rbx);
2649  __ pop(r14);
2650  __ pop(r13);
2651  ExitCode(masm);
2652  __ ret(0);
2653
2654
2655  CodeDesc desc;
2656  masm->GetCode(&desc);
2657  // Call the function from C++.
2658  int result = FUNCTION_CAST<F0>(buffer)();
2659  CHECK_EQ(0, result);
2660}
2661
2662
2663TEST(LoadAndStoreWithRepresentation) {
2664  v8::internal::V8::Initialize(NULL);
2665
2666  // Allocate an executable page of memory.
2667  size_t actual_size;
2668  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
2669                                                 &actual_size,
2670                                                 true));
2671  CHECK(buffer);
2672  Isolate* isolate = CcTest::i_isolate();
2673  HandleScope handles(isolate);
2674  MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size));
2675  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
2676  EntryCode(masm);
2677  __ subq(rsp, Immediate(1 * kPointerSize));
2678  Label exit;
2679
2680  // Test 1.
2681  __ movq(rax, Immediate(1));  // Test number.
2682  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2683  __ movq(rcx, Immediate(-1));
2684  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger8());
2685  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2686  __ movl(rdx, Immediate(255));
2687  __ cmpq(rcx, rdx);
2688  __ j(not_equal, &exit);
2689  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger8());
2690  __ cmpq(rcx, rdx);
2691  __ j(not_equal, &exit);
2692
2693  // Test 2.
2694  __ movq(rax, Immediate(2));  // Test number.
2695  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2696  __ Set(rcx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2697  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Smi());
2698  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2699  __ Set(rdx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678));
2700  __ cmpq(rcx, rdx);
2701  __ j(not_equal, &exit);
2702  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Smi());
2703  __ cmpq(rcx, rdx);
2704  __ j(not_equal, &exit);
2705
2706  // Test 3.
2707  __ movq(rax, Immediate(3));  // Test number.
2708  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2709  __ movq(rcx, Immediate(-1));
2710  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer32());
2711  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2712  __ movl(rdx, Immediate(-1));
2713  __ cmpq(rcx, rdx);
2714  __ j(not_equal, &exit);
2715  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer32());
2716  __ cmpq(rcx, rdx);
2717  __ j(not_equal, &exit);
2718
2719  // Test 4.
2720  __ movq(rax, Immediate(4));  // Test number.
2721  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2722  __ movl(rcx, Immediate(0x44332211));
2723  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::HeapObject());
2724  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2725  __ movl(rdx, Immediate(0x44332211));
2726  __ cmpq(rcx, rdx);
2727  __ j(not_equal, &exit);
2728  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::HeapObject());
2729  __ cmpq(rcx, rdx);
2730  __ j(not_equal, &exit);
2731
2732  // Test 5.
2733  __ movq(rax, Immediate(5));  // Test number.
2734  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2735  __ Set(rcx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2736  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Tagged());
2737  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2738  __ Set(rdx, V8_2PART_UINT64_C(0x12345678, deadbeaf));
2739  __ cmpq(rcx, rdx);
2740  __ j(not_equal, &exit);
2741  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Tagged());
2742  __ cmpq(rcx, rdx);
2743  __ j(not_equal, &exit);
2744
2745  // Test 6.
2746  __ movq(rax, Immediate(6));  // Test number.
2747  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2748  __ Set(rcx, V8_2PART_UINT64_C(0x11223344, 55667788));
2749  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::External());
2750  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2751  __ Set(rdx, V8_2PART_UINT64_C(0x11223344, 55667788));
2752  __ cmpq(rcx, rdx);
2753  __ j(not_equal, &exit);
2754  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::External());
2755  __ cmpq(rcx, rdx);
2756  __ j(not_equal, &exit);
2757
2758  // Test 7.
2759  __ movq(rax, Immediate(7));  // Test number.
2760  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2761  __ movq(rcx, Immediate(-1));
2762  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer8());
2763  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2764  __ movl(rdx, Immediate(255));
2765  __ cmpq(rcx, rdx);
2766  __ j(not_equal, &exit);
2767  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer8());
2768  __ movq(rcx, Immediate(-1));
2769  __ cmpq(rcx, rdx);
2770  __ j(not_equal, &exit);
2771
2772  // Test 8.
2773  __ movq(rax, Immediate(8));  // Test number.
2774  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2775  __ movq(rcx, Immediate(-1));
2776  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer16());
2777  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2778  __ movl(rdx, Immediate(65535));
2779  __ cmpq(rcx, rdx);
2780  __ j(not_equal, &exit);
2781  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer16());
2782  __ movq(rcx, Immediate(-1));
2783  __ cmpq(rcx, rdx);
2784  __ j(not_equal, &exit);
2785
2786  // Test 9.
2787  __ movq(rax, Immediate(9));  // Test number.
2788  __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0));
2789  __ movq(rcx, Immediate(-1));
2790  __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger16());
2791  __ movq(rcx, Operand(rsp, 0 * kPointerSize));
2792  __ movl(rdx, Immediate(65535));
2793  __ cmpq(rcx, rdx);
2794  __ j(not_equal, &exit);
2795  __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger16());
2796  __ cmpq(rcx, rdx);
2797  __ j(not_equal, &exit);
2798
2799  __ xor_(rax, rax);  // Success.
2800  __ bind(&exit);
2801  __ addq(rsp, Immediate(1 * kPointerSize));
2802  ExitCode(masm);
2803  __ ret(0);
2804
2805  CodeDesc desc;
2806  masm->GetCode(&desc);
2807  // Call the function from C++.
2808  int result = FUNCTION_CAST<F0>(buffer)();
2809  CHECK_EQ(0, result);
2810}
2811
2812
2813#undef __
2814