1// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "macro-assembler.h"
33#include "factory.h"
34#include "platform.h"
35#include "serialize.h"
36#include "cctest.h"
37
38using v8::internal::byte;
39using v8::internal::OS;
40using v8::internal::Assembler;
41using v8::internal::Condition;
42using v8::internal::MacroAssembler;
43using v8::internal::HandleScope;
44using v8::internal::Operand;
45using v8::internal::Immediate;
46using v8::internal::SmiIndex;
47using v8::internal::Label;
48using v8::internal::RelocInfo;
49using v8::internal::rax;
50using v8::internal::rbx;
51using v8::internal::rsi;
52using v8::internal::rdi;
53using v8::internal::rcx;
54using v8::internal::rdx;
55using v8::internal::rbp;
56using v8::internal::rsp;
57using v8::internal::r8;
58using v8::internal::r9;
59using v8::internal::r11;
60using v8::internal::r12;  // Remember: r12..r15 are callee save!
61using v8::internal::r13;
62using v8::internal::r14;
63using v8::internal::r15;
64using v8::internal::FUNCTION_CAST;
65using v8::internal::CodeDesc;
66using v8::internal::less_equal;
67using v8::internal::not_equal;
68using v8::internal::not_zero;
69using v8::internal::greater;
70using v8::internal::greater_equal;
71using v8::internal::carry;
72using v8::internal::not_carry;
73using v8::internal::negative;
74using v8::internal::positive;
75using v8::internal::Smi;
76using v8::internal::kSmiTagMask;
77using v8::internal::kSmiValueSize;
78
79// Test the x64 assembler by compiling some simple functions into
80// a buffer and executing them.  These tests do not initialize the
81// V8 library, create a context, or use any V8 objects.
82// The AMD64 calling convention is used, with the first five arguments
83// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in
84// the XMM registers.  The return value is in RAX.
85// This calling convention is used on Linux, with GCC, and on Mac OS,
86// with GCC.  A different convention is used on 64-bit windows.
87
88typedef int (*F0)();
89
90#define __ masm->
91
92TEST(Smi) {
93  // Check that C++ Smi operations work as expected.
94  int64_t test_numbers[] = {
95      0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257,
96      Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1,
97      Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1
98  };
99  int test_number_count = 15;
100  for (int i = 0; i < test_number_count; i++) {
101    int64_t number = test_numbers[i];
102    bool is_valid = Smi::IsValid(number);
103    bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue;
104    CHECK_EQ(is_in_range, is_valid);
105    if (is_valid) {
106      Smi* smi_from_intptr = Smi::FromIntptr(number);
107      if (static_cast<int>(number) == number) {  // Is a 32-bit int.
108        Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number));
109        CHECK_EQ(smi_from_int, smi_from_intptr);
110      }
111      int64_t smi_value = smi_from_intptr->value();
112      CHECK_EQ(number, smi_value);
113    }
114  }
115}
116
117
118static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) {
119  __ movl(rax, Immediate(id));
120  __ Move(rcx, Smi::FromInt(0));
121  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
122  __ cmpq(rcx, rdx);
123  __ j(not_equal, exit);
124}
125
126
127// Test that we can move a Smi value literally into a register.
128TEST(SmiMove) {
129  // Allocate an executable page of memory.
130  size_t actual_size;
131  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
132                                                   &actual_size,
133                                                   true));
134  CHECK(buffer);
135  HandleScope handles;
136  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
137  MacroAssembler* masm = &assembler;  // Create a pointer for the __ macro.
138  masm->set_allow_stub_calls(false);
139  Label exit;
140
141  TestMoveSmi(masm, &exit, 1, Smi::FromInt(0));
142  TestMoveSmi(masm, &exit, 2, Smi::FromInt(127));
143  TestMoveSmi(masm, &exit, 3, Smi::FromInt(128));
144  TestMoveSmi(masm, &exit, 4, Smi::FromInt(255));
145  TestMoveSmi(masm, &exit, 5, Smi::FromInt(256));
146  TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue));
147  TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1));
148  TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128));
149  TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129));
150  TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256));
151  TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257));
152  TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue));
153
154  __ xor_(rax, rax);  // Success.
155  __ bind(&exit);
156  __ ret(0);
157
158  CodeDesc desc;
159  masm->GetCode(&desc);
160  // Call the function from C++.
161  int result = FUNCTION_CAST<F0>(buffer)();
162  CHECK_EQ(0, result);
163}
164
165
166void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) {
167  __ Move(rcx, Smi::FromInt(x));
168  __ movq(r8, rcx);
169  __ Move(rdx, Smi::FromInt(y));
170  __ movq(r9, rdx);
171  __ SmiCompare(rcx, rdx);
172  if (x < y) {
173    __ movl(rax, Immediate(id + 1));
174    __ j(greater_equal, exit);
175  } else if (x > y) {
176    __ movl(rax, Immediate(id + 2));
177    __ j(less_equal, exit);
178  } else {
179    ASSERT_EQ(x, y);
180    __ movl(rax, Immediate(id + 3));
181    __ j(not_equal, exit);
182  }
183  __ movl(rax, Immediate(id + 4));
184  __ cmpq(rcx, r8);
185  __ j(not_equal, exit);
186  __ incq(rax);
187  __ cmpq(rdx, r9);
188  __ j(not_equal, exit);
189
190  if (x != y) {
191    __ SmiCompare(rdx, rcx);
192    if (y < x) {
193      __ movl(rax, Immediate(id + 9));
194      __ j(greater_equal, exit);
195    } else {
196      ASSERT(y > x);
197      __ movl(rax, Immediate(id + 10));
198      __ j(less_equal, exit);
199    }
200  } else {
201    __ SmiCompare(rcx, rcx);
202    __ movl(rax, Immediate(id + 11));
203    __ j(not_equal, exit);
204    __ incq(rax);
205    __ cmpq(rcx, r8);
206    __ j(not_equal, exit);
207  }
208}
209
210
211// Test that we can compare smis for equality (and more).
212TEST(SmiCompare) {
213  // Allocate an executable page of memory.
214  size_t actual_size;
215  byte* buffer =
216      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
217                                      &actual_size,
218                                      true));
219  CHECK(buffer);
220  HandleScope handles;
221  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
222
223  MacroAssembler* masm = &assembler;
224  masm->set_allow_stub_calls(false);
225  Label exit;
226
227  TestSmiCompare(masm, &exit, 0x10, 0, 0);
228  TestSmiCompare(masm, &exit, 0x20, 0, 1);
229  TestSmiCompare(masm, &exit, 0x30, 1, 0);
230  TestSmiCompare(masm, &exit, 0x40, 1, 1);
231  TestSmiCompare(masm, &exit, 0x50, 0, -1);
232  TestSmiCompare(masm, &exit, 0x60, -1, 0);
233  TestSmiCompare(masm, &exit, 0x70, -1, -1);
234  TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue);
235  TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0);
236  TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue);
237  TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0);
238  TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue);
239  TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1);
240  TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue);
241  TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1);
242  TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue);
243  TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue);
244  TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue);
245  TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue);
246
247  __ xor_(rax, rax);  // Success.
248  __ bind(&exit);
249  __ ret(0);
250
251  CodeDesc desc;
252  masm->GetCode(&desc);
253  // Call the function from C++.
254  int result = FUNCTION_CAST<F0>(buffer)();
255  CHECK_EQ(0, result);
256}
257
258
259
260TEST(Integer32ToSmi) {
261  // Allocate an executable page of memory.
262  size_t actual_size;
263  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
264                                                 &actual_size,
265                                                 true));
266  CHECK(buffer);
267  HandleScope handles;
268  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
269
270  MacroAssembler* masm = &assembler;
271  masm->set_allow_stub_calls(false);
272  Label exit;
273
274  __ movq(rax, Immediate(1));  // Test number.
275  __ movl(rcx, Immediate(0));
276  __ Integer32ToSmi(rcx, rcx);
277  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
278  __ SmiCompare(rcx, rdx);
279  __ j(not_equal, &exit);
280
281  __ movq(rax, Immediate(2));  // Test number.
282  __ movl(rcx, Immediate(1024));
283  __ Integer32ToSmi(rcx, rcx);
284  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
285  __ SmiCompare(rcx, rdx);
286  __ j(not_equal, &exit);
287
288  __ movq(rax, Immediate(3));  // Test number.
289  __ movl(rcx, Immediate(-1));
290  __ Integer32ToSmi(rcx, rcx);
291  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
292  __ SmiCompare(rcx, rdx);
293  __ j(not_equal, &exit);
294
295  __ movq(rax, Immediate(4));  // Test number.
296  __ movl(rcx, Immediate(Smi::kMaxValue));
297  __ Integer32ToSmi(rcx, rcx);
298  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
299  __ SmiCompare(rcx, rdx);
300  __ j(not_equal, &exit);
301
302  __ movq(rax, Immediate(5));  // Test number.
303  __ movl(rcx, Immediate(Smi::kMinValue));
304  __ Integer32ToSmi(rcx, rcx);
305  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
306  __ SmiCompare(rcx, rdx);
307  __ j(not_equal, &exit);
308
309  // Different target register.
310
311  __ movq(rax, Immediate(6));  // Test number.
312  __ movl(rcx, Immediate(0));
313  __ Integer32ToSmi(r8, rcx);
314  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0)));
315  __ SmiCompare(r8, rdx);
316  __ j(not_equal, &exit);
317
318  __ movq(rax, Immediate(7));  // Test number.
319  __ movl(rcx, Immediate(1024));
320  __ Integer32ToSmi(r8, rcx);
321  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024)));
322  __ SmiCompare(r8, rdx);
323  __ j(not_equal, &exit);
324
325  __ movq(rax, Immediate(8));  // Test number.
326  __ movl(rcx, Immediate(-1));
327  __ Integer32ToSmi(r8, rcx);
328  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1)));
329  __ SmiCompare(r8, rdx);
330  __ j(not_equal, &exit);
331
332  __ movq(rax, Immediate(9));  // Test number.
333  __ movl(rcx, Immediate(Smi::kMaxValue));
334  __ Integer32ToSmi(r8, rcx);
335  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue)));
336  __ SmiCompare(r8, rdx);
337  __ j(not_equal, &exit);
338
339  __ movq(rax, Immediate(10));  // Test number.
340  __ movl(rcx, Immediate(Smi::kMinValue));
341  __ Integer32ToSmi(r8, rcx);
342  __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue)));
343  __ SmiCompare(r8, rdx);
344  __ j(not_equal, &exit);
345
346
347  __ xor_(rax, rax);  // Success.
348  __ bind(&exit);
349  __ ret(0);
350
351  CodeDesc desc;
352  masm->GetCode(&desc);
353  // Call the function from C++.
354  int result = FUNCTION_CAST<F0>(buffer)();
355  CHECK_EQ(0, result);
356}
357
358
359void TestI64PlusConstantToSmi(MacroAssembler* masm,
360                              Label* exit,
361                              int id,
362                              int64_t x,
363                              int y) {
364  int64_t result = x + y;
365  ASSERT(Smi::IsValid(result));
366  __ movl(rax, Immediate(id));
367  __ Move(r8, Smi::FromInt(static_cast<int>(result)));
368  __ movq(rcx, x, RelocInfo::NONE);
369  __ movq(r11, rcx);
370  __ Integer64PlusConstantToSmi(rdx, rcx, y);
371  __ SmiCompare(rdx, r8);
372  __ j(not_equal, exit);
373
374  __ incq(rax);
375  __ SmiCompare(r11, rcx);
376  __ j(not_equal, exit);
377
378  __ incq(rax);
379  __ Integer64PlusConstantToSmi(rcx, rcx, y);
380  __ SmiCompare(rcx, r8);
381  __ j(not_equal, exit);
382}
383
384
385TEST(Integer64PlusConstantToSmi) {
386  // Allocate an executable page of memory.
387  size_t actual_size;
388  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
389                                                 &actual_size,
390                                                 true));
391  CHECK(buffer);
392  HandleScope handles;
393  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
394
395  MacroAssembler* masm = &assembler;
396  masm->set_allow_stub_calls(false);
397  Label exit;
398
399  int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2;
400
401  TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0);
402  TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1);
403  TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0);
404  TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5);
405  TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5);
406  TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue);
407  TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue);
408  TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue);
409  TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue);
410  TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0);
411  TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0);
412  TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue);
413
414  __ xor_(rax, rax);  // Success.
415  __ bind(&exit);
416  __ ret(0);
417
418  CodeDesc desc;
419  masm->GetCode(&desc);
420  // Call the function from C++.
421  int result = FUNCTION_CAST<F0>(buffer)();
422  CHECK_EQ(0, result);
423}
424
425
426TEST(SmiCheck) {
427  // Allocate an executable page of memory.
428  size_t actual_size;
429  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
430                                                   &actual_size,
431                                                   true));
432  CHECK(buffer);
433  HandleScope handles;
434  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
435
436  MacroAssembler* masm = &assembler;
437  masm->set_allow_stub_calls(false);
438  Label exit;
439  Condition cond;
440
441  __ movl(rax, Immediate(1));  // Test number.
442
443  // CheckSmi
444
445  __ movl(rcx, Immediate(0));
446  __ Integer32ToSmi(rcx, rcx);
447  cond = masm->CheckSmi(rcx);
448  __ j(NegateCondition(cond), &exit);
449
450  __ incq(rax);
451  __ xor_(rcx, Immediate(kSmiTagMask));
452  cond = masm->CheckSmi(rcx);
453  __ j(cond, &exit);
454
455  __ incq(rax);
456  __ movl(rcx, Immediate(-1));
457  __ Integer32ToSmi(rcx, rcx);
458  cond = masm->CheckSmi(rcx);
459  __ j(NegateCondition(cond), &exit);
460
461  __ incq(rax);
462  __ xor_(rcx, Immediate(kSmiTagMask));
463  cond = masm->CheckSmi(rcx);
464  __ j(cond, &exit);
465
466  __ incq(rax);
467  __ movl(rcx, Immediate(Smi::kMaxValue));
468  __ Integer32ToSmi(rcx, rcx);
469  cond = masm->CheckSmi(rcx);
470  __ j(NegateCondition(cond), &exit);
471
472  __ incq(rax);
473  __ xor_(rcx, Immediate(kSmiTagMask));
474  cond = masm->CheckSmi(rcx);
475  __ j(cond, &exit);
476
477  __ incq(rax);
478  __ movl(rcx, Immediate(Smi::kMinValue));
479  __ Integer32ToSmi(rcx, rcx);
480  cond = masm->CheckSmi(rcx);
481  __ j(NegateCondition(cond), &exit);
482
483  __ incq(rax);
484  __ xor_(rcx, Immediate(kSmiTagMask));
485  cond = masm->CheckSmi(rcx);
486  __ j(cond, &exit);
487
488  // CheckPositiveSmi
489
490  __ incq(rax);
491  __ movl(rcx, Immediate(0));
492  __ Integer32ToSmi(rcx, rcx);
493  cond = masm->CheckPositiveSmi(rcx);  // Zero counts as positive.
494  __ j(NegateCondition(cond), &exit);
495
496  __ incq(rax);
497  __ xor_(rcx, Immediate(kSmiTagMask));
498  cond = masm->CheckPositiveSmi(rcx);  // "zero" non-smi.
499  __ j(cond, &exit);
500
501  __ incq(rax);
502  __ movq(rcx, Immediate(-1));
503  __ Integer32ToSmi(rcx, rcx);
504  cond = masm->CheckPositiveSmi(rcx);  // Negative smis are not positive.
505  __ j(cond, &exit);
506
507  __ incq(rax);
508  __ movq(rcx, Immediate(Smi::kMinValue));
509  __ Integer32ToSmi(rcx, rcx);
510  cond = masm->CheckPositiveSmi(rcx);  // Most negative smi is not positive.
511  __ j(cond, &exit);
512
513  __ incq(rax);
514  __ xor_(rcx, Immediate(kSmiTagMask));
515  cond = masm->CheckPositiveSmi(rcx);  // "Negative" non-smi.
516  __ j(cond, &exit);
517
518  __ incq(rax);
519  __ movq(rcx, Immediate(Smi::kMaxValue));
520  __ Integer32ToSmi(rcx, rcx);
521  cond = masm->CheckPositiveSmi(rcx);  // Most positive smi is positive.
522  __ j(NegateCondition(cond), &exit);
523
524  __ incq(rax);
525  __ xor_(rcx, Immediate(kSmiTagMask));
526  cond = masm->CheckPositiveSmi(rcx);  // "Positive" non-smi.
527  __ j(cond, &exit);
528
529  // CheckIsMinSmi
530
531  __ incq(rax);
532  __ movq(rcx, Immediate(Smi::kMaxValue));
533  __ Integer32ToSmi(rcx, rcx);
534  cond = masm->CheckIsMinSmi(rcx);
535  __ j(cond, &exit);
536
537  __ incq(rax);
538  __ movq(rcx, Immediate(0));
539  __ Integer32ToSmi(rcx, rcx);
540  cond = masm->CheckIsMinSmi(rcx);
541  __ j(cond, &exit);
542
543  __ incq(rax);
544  __ movq(rcx, Immediate(Smi::kMinValue));
545  __ Integer32ToSmi(rcx, rcx);
546  cond = masm->CheckIsMinSmi(rcx);
547  __ j(NegateCondition(cond), &exit);
548
549  __ incq(rax);
550  __ movq(rcx, Immediate(Smi::kMinValue + 1));
551  __ Integer32ToSmi(rcx, rcx);
552  cond = masm->CheckIsMinSmi(rcx);
553  __ j(cond, &exit);
554
555  // CheckBothSmi
556
557  __ incq(rax);
558  __ movq(rcx, Immediate(Smi::kMaxValue));
559  __ Integer32ToSmi(rcx, rcx);
560  __ movq(rdx, Immediate(Smi::kMinValue));
561  __ Integer32ToSmi(rdx, rdx);
562  cond = masm->CheckBothSmi(rcx, rdx);
563  __ j(NegateCondition(cond), &exit);
564
565  __ incq(rax);
566  __ xor_(rcx, Immediate(kSmiTagMask));
567  cond = masm->CheckBothSmi(rcx, rdx);
568  __ j(cond, &exit);
569
570  __ incq(rax);
571  __ xor_(rdx, Immediate(kSmiTagMask));
572  cond = masm->CheckBothSmi(rcx, rdx);
573  __ j(cond, &exit);
574
575  __ incq(rax);
576  __ xor_(rcx, Immediate(kSmiTagMask));
577  cond = masm->CheckBothSmi(rcx, rdx);
578  __ j(cond, &exit);
579
580  __ incq(rax);
581  cond = masm->CheckBothSmi(rcx, rcx);
582  __ j(NegateCondition(cond), &exit);
583
584  __ incq(rax);
585  cond = masm->CheckBothSmi(rdx, rdx);
586  __ j(cond, &exit);
587
588  // CheckInteger32ValidSmiValue
589  __ incq(rax);
590  __ movq(rcx, Immediate(0));
591  cond = masm->CheckInteger32ValidSmiValue(rax);
592  __ j(NegateCondition(cond), &exit);
593
594  __ incq(rax);
595  __ movq(rcx, Immediate(-1));
596  cond = masm->CheckInteger32ValidSmiValue(rax);
597  __ j(NegateCondition(cond), &exit);
598
599  __ incq(rax);
600  __ movq(rcx, Immediate(Smi::kMaxValue));
601  cond = masm->CheckInteger32ValidSmiValue(rax);
602  __ j(NegateCondition(cond), &exit);
603
604  __ incq(rax);
605  __ movq(rcx, Immediate(Smi::kMinValue));
606  cond = masm->CheckInteger32ValidSmiValue(rax);
607  __ j(NegateCondition(cond), &exit);
608
609  // Success
610  __ xor_(rax, rax);
611
612  __ bind(&exit);
613  __ ret(0);
614
615  CodeDesc desc;
616  masm->GetCode(&desc);
617  // Call the function from C++.
618  int result = FUNCTION_CAST<F0>(buffer)();
619  CHECK_EQ(0, result);
620}
621
622
623
624void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) {
625  __ Move(rcx, Smi::FromInt(x));
626  __ movq(r11, rcx);
627  if (x == Smi::kMinValue || x == 0) {
628    // Negation fails.
629    __ movl(rax, Immediate(id + 8));
630    __ SmiNeg(r9, rcx, exit);
631
632    __ incq(rax);
633    __ SmiCompare(r11, rcx);
634    __ j(not_equal, exit);
635
636    __ incq(rax);
637    __ SmiNeg(rcx, rcx, exit);
638
639    __ incq(rax);
640    __ SmiCompare(r11, rcx);
641    __ j(not_equal, exit);
642  } else {
643    Label smi_ok, smi_ok2;
644    int result = -x;
645    __ movl(rax, Immediate(id));
646    __ Move(r8, Smi::FromInt(result));
647
648    __ SmiNeg(r9, rcx, &smi_ok);
649    __ jmp(exit);
650    __ bind(&smi_ok);
651    __ incq(rax);
652    __ SmiCompare(r9, r8);
653    __ j(not_equal, exit);
654
655    __ incq(rax);
656    __ SmiCompare(r11, rcx);
657    __ j(not_equal, exit);
658
659    __ incq(rax);
660    __ SmiNeg(rcx, rcx, &smi_ok2);
661    __ jmp(exit);
662    __ bind(&smi_ok2);
663    __ incq(rax);
664    __ SmiCompare(rcx, r8);
665    __ j(not_equal, exit);
666  }
667}
668
669
670TEST(SmiNeg) {
671  // Allocate an executable page of memory.
672  size_t actual_size;
673  byte* buffer =
674      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
675                                      &actual_size,
676                                      true));
677  CHECK(buffer);
678  HandleScope handles;
679  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
680
681  MacroAssembler* masm = &assembler;
682  masm->set_allow_stub_calls(false);
683  Label exit;
684
685  TestSmiNeg(masm, &exit, 0x10, 0);
686  TestSmiNeg(masm, &exit, 0x20, 1);
687  TestSmiNeg(masm, &exit, 0x30, -1);
688  TestSmiNeg(masm, &exit, 0x40, 127);
689  TestSmiNeg(masm, &exit, 0x50, 65535);
690  TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue);
691  TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue);
692  TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue);
693
694  __ xor_(rax, rax);  // Success.
695  __ bind(&exit);
696  __ ret(0);
697
698  CodeDesc desc;
699  masm->GetCode(&desc);
700  // Call the function from C++.
701  int result = FUNCTION_CAST<F0>(buffer)();
702  CHECK_EQ(0, result);
703}
704
705
706
707
708static void SmiAddTest(MacroAssembler* masm,
709                       Label* exit,
710                       int id,
711                       int first,
712                       int second) {
713  __ movl(rcx, Immediate(first));
714  __ Integer32ToSmi(rcx, rcx);
715  __ movl(rdx, Immediate(second));
716  __ Integer32ToSmi(rdx, rdx);
717  __ movl(r8, Immediate(first + second));
718  __ Integer32ToSmi(r8, r8);
719
720  __ movl(rax, Immediate(id));  // Test number.
721  __ SmiAdd(r9, rcx, rdx, exit);
722  __ SmiCompare(r9, r8);
723  __ j(not_equal, exit);
724
725  __ incq(rax);
726  __ SmiAdd(rcx, rcx, rdx, exit);                              \
727  __ SmiCompare(rcx, r8);
728  __ j(not_equal, exit);
729
730  __ movl(rcx, Immediate(first));
731  __ Integer32ToSmi(rcx, rcx);
732
733  __ incq(rax);
734  __ SmiAddConstant(r9, rcx, Smi::FromInt(second));
735  __ SmiCompare(r9, r8);
736  __ j(not_equal, exit);
737
738  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second));
739  __ SmiCompare(rcx, r8);
740  __ j(not_equal, exit);
741
742  __ movl(rcx, Immediate(first));
743  __ Integer32ToSmi(rcx, rcx);
744
745  __ incq(rax);
746  __ SmiAddConstant(r9, rcx, Smi::FromInt(second), exit);
747  __ SmiCompare(r9, r8);
748  __ j(not_equal, exit);
749
750  __ incq(rax);
751  __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), exit);
752  __ SmiCompare(rcx, r8);
753  __ j(not_equal, exit);
754}
755
756TEST(SmiAdd) {
757  // Allocate an executable page of memory.
758  size_t actual_size;
759  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
760                                                 &actual_size,
761                                                 true));
762  CHECK(buffer);
763  HandleScope handles;
764  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
765
766  MacroAssembler* masm = &assembler;
767  masm->set_allow_stub_calls(false);
768  Label exit;
769
770  // No-overflow tests.
771  SmiAddTest(masm, &exit, 0x10, 1, 2);
772  SmiAddTest(masm, &exit, 0x20, 1, -2);
773  SmiAddTest(masm, &exit, 0x30, -1, 2);
774  SmiAddTest(masm, &exit, 0x40, -1, -2);
775  SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000);
776  SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5);
777  SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5);
778  SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue);
779
780  __ xor_(rax, rax);  // Success.
781  __ bind(&exit);
782  __ ret(0);
783
784  CodeDesc desc;
785  masm->GetCode(&desc);
786  // Call the function from C++.
787  int result = FUNCTION_CAST<F0>(buffer)();
788  CHECK_EQ(0, result);
789}
790
791
792static void SmiSubTest(MacroAssembler* masm,
793                      Label* exit,
794                      int id,
795                      int first,
796                      int second) {
797  __ Move(rcx, Smi::FromInt(first));
798  __ Move(rdx, Smi::FromInt(second));
799  __ Move(r8, Smi::FromInt(first - second));
800
801  __ movl(rax, Immediate(id));  // Test 0.
802  __ SmiSub(r9, rcx, rdx, exit);
803  __ SmiCompare(r9, r8);
804  __ j(not_equal, exit);
805
806  __ incq(rax);  // Test 1.
807  __ SmiSub(rcx, rcx, rdx, exit);
808  __ SmiCompare(rcx, r8);
809  __ j(not_equal, exit);
810
811  __ Move(rcx, Smi::FromInt(first));
812
813  __ incq(rax);  // Test 2.
814  __ SmiSubConstant(r9, rcx, Smi::FromInt(second));
815  __ SmiCompare(r9, r8);
816  __ j(not_equal, exit);
817
818  __ incq(rax);  // Test 3.
819  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second));
820  __ SmiCompare(rcx, r8);
821  __ j(not_equal, exit);
822
823  __ Move(rcx, Smi::FromInt(first));
824
825  __ incq(rax);  // Test 4.
826  __ SmiSubConstant(r9, rcx, Smi::FromInt(second), exit);
827  __ SmiCompare(r9, r8);
828  __ j(not_equal, exit);
829
830  __ incq(rax);  // Test 5.
831  __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), exit);
832  __ SmiCompare(rcx, r8);
833  __ j(not_equal, exit);
834}
835
836static void SmiSubOverflowTest(MacroAssembler* masm,
837                               Label* exit,
838                               int id,
839                               int x) {
840  // Subtracts a Smi from x so that the subtraction overflows.
841  ASSERT(x != -1);  // Can't overflow by subtracting a Smi.
842  int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0);
843  int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x);
844
845  __ movl(rax, Immediate(id));
846  __ Move(rcx, Smi::FromInt(x));
847  __ movq(r11, rcx);  // Store original Smi value of x in r11.
848  __ Move(rdx, Smi::FromInt(y_min));
849  {
850    Label overflow_ok;
851    __ SmiSub(r9, rcx, rdx, &overflow_ok);
852    __ jmp(exit);
853    __ bind(&overflow_ok);
854    __ incq(rax);
855    __ SmiCompare(rcx, r11);
856    __ j(not_equal, exit);
857  }
858
859  {
860    Label overflow_ok;
861    __ incq(rax);
862    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
863    __ jmp(exit);
864    __ bind(&overflow_ok);
865    __ incq(rax);
866    __ SmiCompare(rcx, r11);
867    __ j(not_equal, exit);
868  }
869
870  __ movq(rcx, r11);
871  {
872    Label overflow_ok;
873    __ incq(rax);
874    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok);
875    __ jmp(exit);
876    __ bind(&overflow_ok);
877    __ incq(rax);
878    __ SmiCompare(rcx, r11);
879    __ j(not_equal, exit);
880  }
881
882  {
883    Label overflow_ok;
884    __ incq(rax);
885    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok);
886    __ jmp(exit);
887    __ bind(&overflow_ok);
888    __ incq(rax);
889    __ SmiCompare(rcx, r11);
890    __ j(not_equal, exit);
891  }
892
893  __ Move(rdx, Smi::FromInt(y_max));
894
895  {
896    Label overflow_ok;
897    __ incq(rax);
898    __ SmiSub(r9, rcx, rdx, &overflow_ok);
899    __ jmp(exit);
900    __ bind(&overflow_ok);
901    __ incq(rax);
902    __ SmiCompare(rcx, r11);
903    __ j(not_equal, exit);
904  }
905
906  {
907    Label overflow_ok;
908    __ incq(rax);
909    __ SmiSub(rcx, rcx, rdx, &overflow_ok);
910    __ jmp(exit);
911    __ bind(&overflow_ok);
912    __ incq(rax);
913    __ SmiCompare(rcx, r11);
914    __ j(not_equal, exit);
915  }
916
917  __ movq(rcx, r11);
918  {
919    Label overflow_ok;
920    __ incq(rax);
921    __ SmiSubConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok);
922    __ jmp(exit);
923    __ bind(&overflow_ok);
924    __ incq(rax);
925    __ SmiCompare(rcx, r11);
926    __ j(not_equal, exit);
927  }
928
929  {
930    Label overflow_ok;
931    __ incq(rax);
932    __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok);
933    __ jmp(exit);
934    __ bind(&overflow_ok);
935    __ incq(rax);
936    __ SmiCompare(rcx, r11);
937    __ j(not_equal, exit);
938  }
939}
940
941
942TEST(SmiSub) {
943  // Allocate an executable page of memory.
944  size_t actual_size;
945  byte* buffer =
946      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
947                                      &actual_size,
948                                      true));
949  CHECK(buffer);
950  HandleScope handles;
951  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
952
953  MacroAssembler* masm = &assembler;
954  masm->set_allow_stub_calls(false);
955  Label exit;
956
957  SmiSubTest(masm, &exit, 0x10, 1, 2);
958  SmiSubTest(masm, &exit, 0x20, 1, -2);
959  SmiSubTest(masm, &exit, 0x30, -1, 2);
960  SmiSubTest(masm, &exit, 0x40, -1, -2);
961  SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000);
962  SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5);
963  SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5);
964  SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue);
965  SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue);
966
967  SmiSubOverflowTest(masm, &exit, 0xA0, 1);
968  SmiSubOverflowTest(masm, &exit, 0xB0, 1024);
969  SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue);
970  SmiSubOverflowTest(masm, &exit, 0xD0, -2);
971  SmiSubOverflowTest(masm, &exit, 0xE0, -42000);
972  SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue);
973  SmiSubOverflowTest(masm, &exit, 0x100, 0);
974
975  __ xor_(rax, rax);  // Success.
976  __ bind(&exit);
977  __ ret(0);
978
979  CodeDesc desc;
980  masm->GetCode(&desc);
981  // Call the function from C++.
982  int result = FUNCTION_CAST<F0>(buffer)();
983  CHECK_EQ(0, result);
984}
985
986
987
988void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) {
989  int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y);
990  bool negative_zero = (result == 0) && (x < 0 || y < 0);
991  __ Move(rcx, Smi::FromInt(x));
992  __ movq(r11, rcx);
993  __ Move(rdx, Smi::FromInt(y));
994  if (Smi::IsValid(result) && !negative_zero) {
995    __ movl(rax, Immediate(id));
996    __ Move(r8, Smi::FromIntptr(result));
997    __ SmiMul(r9, rcx, rdx, exit);
998    __ incq(rax);
999    __ SmiCompare(r11, rcx);
1000    __ j(not_equal, exit);
1001    __ incq(rax);
1002    __ SmiCompare(r9, r8);
1003    __ j(not_equal, exit);
1004
1005    __ incq(rax);
1006    __ SmiMul(rcx, rcx, rdx, exit);
1007    __ SmiCompare(rcx, r8);
1008    __ j(not_equal, exit);
1009  } else {
1010    __ movl(rax, Immediate(id + 8));
1011    Label overflow_ok, overflow_ok2;
1012    __ SmiMul(r9, rcx, rdx, &overflow_ok);
1013    __ jmp(exit);
1014    __ bind(&overflow_ok);
1015    __ incq(rax);
1016    __ SmiCompare(r11, rcx);
1017    __ j(not_equal, exit);
1018    __ incq(rax);
1019    __ SmiMul(rcx, rcx, rdx, &overflow_ok2);
1020    __ jmp(exit);
1021    __ bind(&overflow_ok2);
1022    // 31-bit version doesn't preserve rcx on failure.
1023    // __ incq(rax);
1024    // __ SmiCompare(r11, rcx);
1025    // __ j(not_equal, exit);
1026  }
1027}
1028
1029
1030TEST(SmiMul) {
1031  // Allocate an executable page of memory.
1032  size_t actual_size;
1033  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1034                                                 &actual_size,
1035                                                 true));
1036  CHECK(buffer);
1037  HandleScope handles;
1038  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1039
1040  MacroAssembler* masm = &assembler;
1041  masm->set_allow_stub_calls(false);
1042  Label exit;
1043
1044  TestSmiMul(masm, &exit, 0x10, 0, 0);
1045  TestSmiMul(masm, &exit, 0x20, -1, 0);
1046  TestSmiMul(masm, &exit, 0x30, 0, -1);
1047  TestSmiMul(masm, &exit, 0x40, -1, -1);
1048  TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000);
1049  TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff);
1050  TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff);
1051  TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1);
1052  TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2);
1053  TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2);
1054  TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2);
1055  TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2);
1056  TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2);
1057  TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2);
1058
1059  __ xor_(rax, rax);  // Success.
1060  __ bind(&exit);
1061  __ ret(0);
1062
1063  CodeDesc desc;
1064  masm->GetCode(&desc);
1065  // Call the function from C++.
1066  int result = FUNCTION_CAST<F0>(buffer)();
1067  CHECK_EQ(0, result);
1068}
1069
1070
1071void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1072  bool division_by_zero = (y == 0);
1073  bool negative_zero = (x == 0 && y < 0);
1074#ifdef V8_TARGET_ARCH_X64
1075  bool overflow = (x == Smi::kMinValue && y < 0);  // Safe approx. used.
1076#else
1077  bool overflow = (x == Smi::kMinValue && y == -1);
1078#endif
1079  bool fraction = !division_by_zero && !overflow && (x % y != 0);
1080  __ Move(r11, Smi::FromInt(x));
1081  __ Move(r12, Smi::FromInt(y));
1082  if (!fraction && !overflow && !negative_zero && !division_by_zero) {
1083    // Division succeeds
1084    __ movq(rcx, r11);
1085    __ movq(r15, Immediate(id));
1086    int result = x / y;
1087    __ Move(r8, Smi::FromInt(result));
1088    __ SmiDiv(r9, rcx, r12, exit);
1089    // Might have destroyed rcx and r12.
1090    __ incq(r15);
1091    __ SmiCompare(r9, r8);
1092    __ j(not_equal, exit);
1093
1094    __ incq(r15);
1095    __ movq(rcx, r11);
1096    __ Move(r12, Smi::FromInt(y));
1097    __ SmiCompare(rcx, r11);
1098    __ j(not_equal, exit);
1099
1100    __ incq(r15);
1101    __ SmiDiv(rcx, rcx, r12, exit);
1102
1103    __ incq(r15);
1104    __ SmiCompare(rcx, r8);
1105    __ j(not_equal, exit);
1106  } else {
1107    // Division fails.
1108    __ movq(r15, Immediate(id + 8));
1109
1110    Label fail_ok, fail_ok2;
1111    __ movq(rcx, r11);
1112    __ SmiDiv(r9, rcx, r12, &fail_ok);
1113    __ jmp(exit);
1114    __ bind(&fail_ok);
1115
1116    __ incq(r15);
1117    __ SmiCompare(rcx, r11);
1118    __ j(not_equal, exit);
1119
1120    __ incq(r15);
1121    __ SmiDiv(rcx, rcx, r12, &fail_ok2);
1122    __ jmp(exit);
1123    __ bind(&fail_ok2);
1124
1125    __ incq(r15);
1126    __ SmiCompare(rcx, r11);
1127    __ j(not_equal, exit);
1128  }
1129}
1130
1131
1132TEST(SmiDiv) {
1133  // Allocate an executable page of memory.
1134  size_t actual_size;
1135  byte* buffer =
1136      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1137                                      &actual_size,
1138                                      true));
1139  CHECK(buffer);
1140  HandleScope handles;
1141  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1142
1143  MacroAssembler* masm = &assembler;
1144  masm->set_allow_stub_calls(false);
1145  Label exit;
1146
1147  __ push(r12);
1148  __ push(r15);
1149  TestSmiDiv(masm, &exit, 0x10, 1, 1);
1150  TestSmiDiv(masm, &exit, 0x20, 1, 0);
1151  TestSmiDiv(masm, &exit, 0x30, -1, 0);
1152  TestSmiDiv(masm, &exit, 0x40, 0, 1);
1153  TestSmiDiv(masm, &exit, 0x50, 0, -1);
1154  TestSmiDiv(masm, &exit, 0x60, 4, 2);
1155  TestSmiDiv(masm, &exit, 0x70, -4, 2);
1156  TestSmiDiv(masm, &exit, 0x80, 4, -2);
1157  TestSmiDiv(masm, &exit, 0x90, -4, -2);
1158  TestSmiDiv(masm, &exit, 0xa0, 3, 2);
1159  TestSmiDiv(masm, &exit, 0xb0, 3, 4);
1160  TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1161  TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1162  TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1163  TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1164  TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1165  TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1);
1166  TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1);
1167  TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1168  TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1);
1169
1170  __ xor_(r15, r15);  // Success.
1171  __ bind(&exit);
1172  __ movq(rax, r15);
1173  __ pop(r15);
1174  __ pop(r12);
1175  __ ret(0);
1176
1177  CodeDesc desc;
1178  masm->GetCode(&desc);
1179  // Call the function from C++.
1180  int result = FUNCTION_CAST<F0>(buffer)();
1181  CHECK_EQ(0, result);
1182}
1183
1184
1185void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1186  bool division_by_zero = (y == 0);
1187  bool division_overflow = (x == Smi::kMinValue) && (y == -1);
1188  bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0);
1189  bool negative_zero = (!fraction && x < 0);
1190  __ Move(rcx, Smi::FromInt(x));
1191  __ movq(r11, rcx);
1192  __ Move(r12, Smi::FromInt(y));
1193  if (!division_overflow && !negative_zero && !division_by_zero) {
1194    // Modulo succeeds
1195    __ movq(r15, Immediate(id));
1196    int result = x % y;
1197    __ Move(r8, Smi::FromInt(result));
1198    __ SmiMod(r9, rcx, r12, exit);
1199
1200    __ incq(r15);
1201    __ SmiCompare(r9, r8);
1202    __ j(not_equal, exit);
1203
1204    __ incq(r15);
1205    __ SmiCompare(rcx, r11);
1206    __ j(not_equal, exit);
1207
1208    __ incq(r15);
1209    __ SmiMod(rcx, rcx, r12, exit);
1210
1211    __ incq(r15);
1212    __ SmiCompare(rcx, r8);
1213    __ j(not_equal, exit);
1214  } else {
1215    // Modulo fails.
1216    __ movq(r15, Immediate(id + 8));
1217
1218    Label fail_ok, fail_ok2;
1219    __ SmiMod(r9, rcx, r12, &fail_ok);
1220    __ jmp(exit);
1221    __ bind(&fail_ok);
1222
1223    __ incq(r15);
1224    __ SmiCompare(rcx, r11);
1225    __ j(not_equal, exit);
1226
1227    __ incq(r15);
1228    __ SmiMod(rcx, rcx, r12, &fail_ok2);
1229    __ jmp(exit);
1230    __ bind(&fail_ok2);
1231
1232    __ incq(r15);
1233    __ SmiCompare(rcx, r11);
1234    __ j(not_equal, exit);
1235  }
1236}
1237
1238
1239TEST(SmiMod) {
1240  // Allocate an executable page of memory.
1241  size_t actual_size;
1242  byte* buffer =
1243      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1244                                      &actual_size,
1245                                      true));
1246  CHECK(buffer);
1247  HandleScope handles;
1248  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1249
1250  MacroAssembler* masm = &assembler;
1251  masm->set_allow_stub_calls(false);
1252  Label exit;
1253
1254  __ push(r12);
1255  __ push(r15);
1256  TestSmiMod(masm, &exit, 0x10, 1, 1);
1257  TestSmiMod(masm, &exit, 0x20, 1, 0);
1258  TestSmiMod(masm, &exit, 0x30, -1, 0);
1259  TestSmiMod(masm, &exit, 0x40, 0, 1);
1260  TestSmiMod(masm, &exit, 0x50, 0, -1);
1261  TestSmiMod(masm, &exit, 0x60, 4, 2);
1262  TestSmiMod(masm, &exit, 0x70, -4, 2);
1263  TestSmiMod(masm, &exit, 0x80, 4, -2);
1264  TestSmiMod(masm, &exit, 0x90, -4, -2);
1265  TestSmiMod(masm, &exit, 0xa0, 3, 2);
1266  TestSmiMod(masm, &exit, 0xb0, 3, 4);
1267  TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue);
1268  TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue);
1269  TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1);
1270  TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue);
1271  TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue);
1272  TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1);
1273  TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1);
1274  TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue);
1275  TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1);
1276
1277  __ xor_(r15, r15);  // Success.
1278  __ bind(&exit);
1279  __ movq(rax, r15);
1280  __ pop(r15);
1281  __ pop(r12);
1282  __ ret(0);
1283
1284  CodeDesc desc;
1285  masm->GetCode(&desc);
1286  // Call the function from C++.
1287  int result = FUNCTION_CAST<F0>(buffer)();
1288  CHECK_EQ(0, result);
1289}
1290
1291
1292void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) {
1293  __ movl(rax, Immediate(id));
1294
1295  for (int i = 0; i < 8; i++) {
1296    __ Move(rcx, Smi::FromInt(x));
1297    SmiIndex index = masm->SmiToIndex(rdx, rcx, i);
1298    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1299    __ shl(index.reg, Immediate(index.scale));
1300    __ Set(r8, static_cast<intptr_t>(x) << i);
1301    __ SmiCompare(index.reg, r8);
1302    __ j(not_equal, exit);
1303    __ incq(rax);
1304    __ Move(rcx, Smi::FromInt(x));
1305    index = masm->SmiToIndex(rcx, rcx, i);
1306    ASSERT(index.reg.is(rcx));
1307    __ shl(rcx, Immediate(index.scale));
1308    __ Set(r8, static_cast<intptr_t>(x) << i);
1309    __ SmiCompare(rcx, r8);
1310    __ j(not_equal, exit);
1311    __ incq(rax);
1312
1313    __ Move(rcx, Smi::FromInt(x));
1314    index = masm->SmiToNegativeIndex(rdx, rcx, i);
1315    ASSERT(index.reg.is(rcx) || index.reg.is(rdx));
1316    __ shl(index.reg, Immediate(index.scale));
1317    __ Set(r8, static_cast<intptr_t>(-x) << i);
1318    __ SmiCompare(index.reg, r8);
1319    __ j(not_equal, exit);
1320    __ incq(rax);
1321    __ Move(rcx, Smi::FromInt(x));
1322    index = masm->SmiToNegativeIndex(rcx, rcx, i);
1323    ASSERT(index.reg.is(rcx));
1324    __ shl(rcx, Immediate(index.scale));
1325    __ Set(r8, static_cast<intptr_t>(-x) << i);
1326    __ SmiCompare(rcx, r8);
1327    __ j(not_equal, exit);
1328    __ incq(rax);
1329  }
1330}
1331
1332TEST(SmiIndex) {
1333  // Allocate an executable page of memory.
1334  size_t actual_size;
1335  byte* buffer =
1336      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1337                                      &actual_size,
1338                                      true));
1339  CHECK(buffer);
1340  HandleScope handles;
1341  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1342
1343  MacroAssembler* masm = &assembler;
1344  masm->set_allow_stub_calls(false);
1345  Label exit;
1346
1347  TestSmiIndex(masm, &exit, 0x10, 0);
1348  TestSmiIndex(masm, &exit, 0x20, 1);
1349  TestSmiIndex(masm, &exit, 0x30, 100);
1350  TestSmiIndex(masm, &exit, 0x40, 1000);
1351  TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue);
1352
1353  __ xor_(rax, rax);  // Success.
1354  __ bind(&exit);
1355  __ ret(0);
1356
1357  CodeDesc desc;
1358  masm->GetCode(&desc);
1359  // Call the function from C++.
1360  int result = FUNCTION_CAST<F0>(buffer)();
1361  CHECK_EQ(0, result);
1362}
1363
1364
1365void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1366  __ movl(rax, Immediate(id));
1367  __ Move(rcx, Smi::FromInt(x));
1368  __ Move(rdx, Smi::FromInt(y));
1369  __ xor_(rdx, Immediate(kSmiTagMask));
1370  __ SelectNonSmi(r9, rcx, rdx, exit);
1371
1372  __ incq(rax);
1373  __ SmiCompare(r9, rdx);
1374  __ j(not_equal, exit);
1375
1376  __ incq(rax);
1377  __ Move(rcx, Smi::FromInt(x));
1378  __ Move(rdx, Smi::FromInt(y));
1379  __ xor_(rcx, Immediate(kSmiTagMask));
1380  __ SelectNonSmi(r9, rcx, rdx, exit);
1381
1382  __ incq(rax);
1383  __ SmiCompare(r9, rcx);
1384  __ j(not_equal, exit);
1385
1386  __ incq(rax);
1387  Label fail_ok;
1388  __ Move(rcx, Smi::FromInt(x));
1389  __ Move(rdx, Smi::FromInt(y));
1390  __ xor_(rcx, Immediate(kSmiTagMask));
1391  __ xor_(rdx, Immediate(kSmiTagMask));
1392  __ SelectNonSmi(r9, rcx, rdx, &fail_ok);
1393  __ jmp(exit);
1394  __ bind(&fail_ok);
1395}
1396
1397
1398TEST(SmiSelectNonSmi) {
1399  // Allocate an executable page of memory.
1400  size_t actual_size;
1401  byte* buffer =
1402      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1403                                      &actual_size,
1404                                      true));
1405  CHECK(buffer);
1406  HandleScope handles;
1407  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1408
1409  MacroAssembler* masm = &assembler;
1410  masm->set_allow_stub_calls(false);  // Avoid inline checks.
1411  Label exit;
1412
1413  TestSelectNonSmi(masm, &exit, 0x10, 0, 0);
1414  TestSelectNonSmi(masm, &exit, 0x20, 0, 1);
1415  TestSelectNonSmi(masm, &exit, 0x30, 1, 0);
1416  TestSelectNonSmi(masm, &exit, 0x40, 0, -1);
1417  TestSelectNonSmi(masm, &exit, 0x50, -1, 0);
1418  TestSelectNonSmi(masm, &exit, 0x60, -1, -1);
1419  TestSelectNonSmi(masm, &exit, 0x70, 1, 1);
1420  TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1421  TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1422
1423  __ xor_(rax, rax);  // Success.
1424  __ bind(&exit);
1425  __ ret(0);
1426
1427  CodeDesc desc;
1428  masm->GetCode(&desc);
1429  // Call the function from C++.
1430  int result = FUNCTION_CAST<F0>(buffer)();
1431  CHECK_EQ(0, result);
1432}
1433
1434
1435void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1436  int result = x & y;
1437
1438  __ movl(rax, Immediate(id));
1439
1440  __ Move(rcx, Smi::FromInt(x));
1441  __ movq(r11, rcx);
1442  __ Move(rdx, Smi::FromInt(y));
1443  __ Move(r8, Smi::FromInt(result));
1444  __ SmiAnd(r9, rcx, rdx);
1445  __ SmiCompare(r8, r9);
1446  __ j(not_equal, exit);
1447
1448  __ incq(rax);
1449  __ SmiCompare(r11, rcx);
1450  __ j(not_equal, exit);
1451
1452  __ incq(rax);
1453  __ SmiAnd(rcx, rcx, rdx);
1454  __ SmiCompare(r8, rcx);
1455  __ j(not_equal, exit);
1456
1457  __ movq(rcx, r11);
1458  __ incq(rax);
1459  __ SmiAndConstant(r9, rcx, Smi::FromInt(y));
1460  __ SmiCompare(r8, r9);
1461  __ j(not_equal, exit);
1462
1463  __ incq(rax);
1464  __ SmiCompare(r11, rcx);
1465  __ j(not_equal, exit);
1466
1467  __ incq(rax);
1468  __ SmiAndConstant(rcx, rcx, Smi::FromInt(y));
1469  __ SmiCompare(r8, rcx);
1470  __ j(not_equal, exit);
1471}
1472
1473
1474TEST(SmiAnd) {
1475  // Allocate an executable page of memory.
1476  size_t actual_size;
1477  byte* buffer =
1478      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1479                                      &actual_size,
1480                                      true));
1481  CHECK(buffer);
1482  HandleScope handles;
1483  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1484
1485  MacroAssembler* masm = &assembler;
1486  masm->set_allow_stub_calls(false);
1487  Label exit;
1488
1489  TestSmiAnd(masm, &exit, 0x10, 0, 0);
1490  TestSmiAnd(masm, &exit, 0x20, 0, 1);
1491  TestSmiAnd(masm, &exit, 0x30, 1, 0);
1492  TestSmiAnd(masm, &exit, 0x40, 0, -1);
1493  TestSmiAnd(masm, &exit, 0x50, -1, 0);
1494  TestSmiAnd(masm, &exit, 0x60, -1, -1);
1495  TestSmiAnd(masm, &exit, 0x70, 1, 1);
1496  TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1497  TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1498  TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1);
1499  TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1);
1500
1501  __ xor_(rax, rax);  // Success.
1502  __ bind(&exit);
1503  __ ret(0);
1504
1505  CodeDesc desc;
1506  masm->GetCode(&desc);
1507  // Call the function from C++.
1508  int result = FUNCTION_CAST<F0>(buffer)();
1509  CHECK_EQ(0, result);
1510}
1511
1512
1513void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1514  int result = x | y;
1515
1516  __ movl(rax, Immediate(id));
1517
1518  __ Move(rcx, Smi::FromInt(x));
1519  __ movq(r11, rcx);
1520  __ Move(rdx, Smi::FromInt(y));
1521  __ Move(r8, Smi::FromInt(result));
1522  __ SmiOr(r9, rcx, rdx);
1523  __ SmiCompare(r8, r9);
1524  __ j(not_equal, exit);
1525
1526  __ incq(rax);
1527  __ SmiCompare(r11, rcx);
1528  __ j(not_equal, exit);
1529
1530  __ incq(rax);
1531  __ SmiOr(rcx, rcx, rdx);
1532  __ SmiCompare(r8, rcx);
1533  __ j(not_equal, exit);
1534
1535  __ movq(rcx, r11);
1536  __ incq(rax);
1537  __ SmiOrConstant(r9, rcx, Smi::FromInt(y));
1538  __ SmiCompare(r8, r9);
1539  __ j(not_equal, exit);
1540
1541  __ incq(rax);
1542  __ SmiCompare(r11, rcx);
1543  __ j(not_equal, exit);
1544
1545  __ incq(rax);
1546  __ SmiOrConstant(rcx, rcx, Smi::FromInt(y));
1547  __ SmiCompare(r8, rcx);
1548  __ j(not_equal, exit);
1549}
1550
1551
1552TEST(SmiOr) {
1553  // Allocate an executable page of memory.
1554  size_t actual_size;
1555  byte* buffer =
1556      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1557                                      &actual_size,
1558                                      true));
1559  CHECK(buffer);
1560  HandleScope handles;
1561  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1562
1563  MacroAssembler* masm = &assembler;
1564  masm->set_allow_stub_calls(false);
1565  Label exit;
1566
1567  TestSmiOr(masm, &exit, 0x10, 0, 0);
1568  TestSmiOr(masm, &exit, 0x20, 0, 1);
1569  TestSmiOr(masm, &exit, 0x30, 1, 0);
1570  TestSmiOr(masm, &exit, 0x40, 0, -1);
1571  TestSmiOr(masm, &exit, 0x50, -1, 0);
1572  TestSmiOr(masm, &exit, 0x60, -1, -1);
1573  TestSmiOr(masm, &exit, 0x70, 1, 1);
1574  TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1575  TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1576  TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1);
1577  TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567);
1578  TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9);
1579  TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1);
1580
1581  __ xor_(rax, rax);  // Success.
1582  __ bind(&exit);
1583  __ ret(0);
1584
1585  CodeDesc desc;
1586  masm->GetCode(&desc);
1587  // Call the function from C++.
1588  int result = FUNCTION_CAST<F0>(buffer)();
1589  CHECK_EQ(0, result);
1590}
1591
1592
1593void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) {
1594  int result = x ^ y;
1595
1596  __ movl(rax, Immediate(id));
1597
1598  __ Move(rcx, Smi::FromInt(x));
1599  __ movq(r11, rcx);
1600  __ Move(rdx, Smi::FromInt(y));
1601  __ Move(r8, Smi::FromInt(result));
1602  __ SmiXor(r9, rcx, rdx);
1603  __ SmiCompare(r8, r9);
1604  __ j(not_equal, exit);
1605
1606  __ incq(rax);
1607  __ SmiCompare(r11, rcx);
1608  __ j(not_equal, exit);
1609
1610  __ incq(rax);
1611  __ SmiXor(rcx, rcx, rdx);
1612  __ SmiCompare(r8, rcx);
1613  __ j(not_equal, exit);
1614
1615  __ movq(rcx, r11);
1616  __ incq(rax);
1617  __ SmiXorConstant(r9, rcx, Smi::FromInt(y));
1618  __ SmiCompare(r8, r9);
1619  __ j(not_equal, exit);
1620
1621  __ incq(rax);
1622  __ SmiCompare(r11, rcx);
1623  __ j(not_equal, exit);
1624
1625  __ incq(rax);
1626  __ SmiXorConstant(rcx, rcx, Smi::FromInt(y));
1627  __ SmiCompare(r8, rcx);
1628  __ j(not_equal, exit);
1629}
1630
1631
1632TEST(SmiXor) {
1633  // Allocate an executable page of memory.
1634  size_t actual_size;
1635  byte* buffer =
1636      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1637                                      &actual_size,
1638                                      true));
1639  CHECK(buffer);
1640  HandleScope handles;
1641  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1642
1643  MacroAssembler* masm = &assembler;
1644  masm->set_allow_stub_calls(false);
1645  Label exit;
1646
1647  TestSmiXor(masm, &exit, 0x10, 0, 0);
1648  TestSmiXor(masm, &exit, 0x20, 0, 1);
1649  TestSmiXor(masm, &exit, 0x30, 1, 0);
1650  TestSmiXor(masm, &exit, 0x40, 0, -1);
1651  TestSmiXor(masm, &exit, 0x50, -1, 0);
1652  TestSmiXor(masm, &exit, 0x60, -1, -1);
1653  TestSmiXor(masm, &exit, 0x70, 1, 1);
1654  TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue);
1655  TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue);
1656  TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1);
1657  TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567);
1658  TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9);
1659  TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1);
1660
1661  __ xor_(rax, rax);  // Success.
1662  __ bind(&exit);
1663  __ ret(0);
1664
1665  CodeDesc desc;
1666  masm->GetCode(&desc);
1667  // Call the function from C++.
1668  int result = FUNCTION_CAST<F0>(buffer)();
1669  CHECK_EQ(0, result);
1670}
1671
1672
1673void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) {
1674  int result = ~x;
1675  __ movl(rax, Immediate(id));
1676
1677  __ Move(r8, Smi::FromInt(result));
1678  __ Move(rcx, Smi::FromInt(x));
1679  __ movq(r11, rcx);
1680
1681  __ SmiNot(r9, rcx);
1682  __ SmiCompare(r9, r8);
1683  __ j(not_equal, exit);
1684
1685  __ incq(rax);
1686  __ SmiCompare(r11, rcx);
1687  __ j(not_equal, exit);
1688
1689  __ incq(rax);
1690  __ SmiNot(rcx, rcx);
1691  __ SmiCompare(rcx, r8);
1692  __ j(not_equal, exit);
1693}
1694
1695
1696TEST(SmiNot) {
1697  // Allocate an executable page of memory.
1698  size_t actual_size;
1699  byte* buffer =
1700      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
1701                                      &actual_size,
1702                                      true));
1703  CHECK(buffer);
1704  HandleScope handles;
1705  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1706
1707  MacroAssembler* masm = &assembler;
1708  masm->set_allow_stub_calls(false);
1709  Label exit;
1710
1711  TestSmiNot(masm, &exit, 0x10, 0);
1712  TestSmiNot(masm, &exit, 0x20, 1);
1713  TestSmiNot(masm, &exit, 0x30, -1);
1714  TestSmiNot(masm, &exit, 0x40, 127);
1715  TestSmiNot(masm, &exit, 0x50, 65535);
1716  TestSmiNot(masm, &exit, 0x60, Smi::kMinValue);
1717  TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue);
1718  TestSmiNot(masm, &exit, 0x80, 0x05555555);
1719
1720  __ xor_(rax, rax);  // Success.
1721  __ bind(&exit);
1722  __ ret(0);
1723
1724  CodeDesc desc;
1725  masm->GetCode(&desc);
1726  // Call the function from C++.
1727  int result = FUNCTION_CAST<F0>(buffer)();
1728  CHECK_EQ(0, result);
1729}
1730
1731
1732void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) {
1733  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1734  const int kNumShifts = 5;
1735  __ movl(rax, Immediate(id));
1736  for (int i = 0; i < kNumShifts; i++) {
1737    // rax == id + i * 10.
1738    int shift = shifts[i];
1739    int result = x << shift;
1740    if (Smi::IsValid(result)) {
1741      __ Move(r8, Smi::FromInt(result));
1742      __ Move(rcx, Smi::FromInt(x));
1743      __ SmiShiftLeftConstant(r9, rcx, shift, exit);
1744
1745      __ incq(rax);
1746      __ SmiCompare(r9, r8);
1747      __ j(not_equal, exit);
1748
1749      __ incq(rax);
1750      __ Move(rcx, Smi::FromInt(x));
1751      __ SmiShiftLeftConstant(rcx, rcx, shift, exit);
1752
1753      __ incq(rax);
1754      __ SmiCompare(rcx, r8);
1755      __ j(not_equal, exit);
1756
1757      __ incq(rax);
1758      __ Move(rdx, Smi::FromInt(x));
1759      __ Move(rcx, Smi::FromInt(shift));
1760      __ SmiShiftLeft(r9, rdx, rcx, exit);
1761
1762      __ incq(rax);
1763      __ SmiCompare(r9, r8);
1764      __ j(not_equal, exit);
1765
1766      __ incq(rax);
1767      __ Move(rdx, Smi::FromInt(x));
1768      __ Move(r11, Smi::FromInt(shift));
1769      __ SmiShiftLeft(r9, rdx, r11, exit);
1770
1771      __ incq(rax);
1772      __ SmiCompare(r9, r8);
1773      __ j(not_equal, exit);
1774
1775      __ incq(rax);
1776      __ Move(rdx, Smi::FromInt(x));
1777      __ Move(r11, Smi::FromInt(shift));
1778      __ SmiShiftLeft(rdx, rdx, r11, exit);
1779
1780      __ incq(rax);
1781      __ SmiCompare(rdx, r8);
1782      __ j(not_equal, exit);
1783
1784      __ incq(rax);
1785    } else {
1786      // Cannot happen with long smis.
1787      Label fail_ok;
1788      __ Move(rcx, Smi::FromInt(x));
1789      __ movq(r11, rcx);
1790      __ SmiShiftLeftConstant(r9, rcx, shift, &fail_ok);
1791      __ jmp(exit);
1792      __ bind(&fail_ok);
1793
1794      __ incq(rax);
1795      __ SmiCompare(rcx, r11);
1796      __ j(not_equal, exit);
1797
1798      __ incq(rax);
1799      Label fail_ok2;
1800      __ SmiShiftLeftConstant(rcx, rcx, shift, &fail_ok2);
1801      __ jmp(exit);
1802      __ bind(&fail_ok2);
1803
1804      __ incq(rax);
1805      __ SmiCompare(rcx, r11);
1806      __ j(not_equal, exit);
1807
1808      __ incq(rax);
1809      __ Move(r8, Smi::FromInt(shift));
1810      Label fail_ok3;
1811      __ SmiShiftLeft(r9, rcx, r8, &fail_ok3);
1812      __ jmp(exit);
1813      __ bind(&fail_ok3);
1814
1815      __ incq(rax);
1816      __ SmiCompare(rcx, r11);
1817      __ j(not_equal, exit);
1818
1819      __ incq(rax);
1820      __ Move(r8, Smi::FromInt(shift));
1821      __ movq(rdx, r11);
1822      Label fail_ok4;
1823      __ SmiShiftLeft(rdx, rdx, r8, &fail_ok4);
1824      __ jmp(exit);
1825      __ bind(&fail_ok4);
1826
1827      __ incq(rax);
1828      __ SmiCompare(rdx, r11);
1829      __ j(not_equal, exit);
1830
1831      __ addq(rax, Immediate(3));
1832    }
1833  }
1834}
1835
1836
1837TEST(SmiShiftLeft) {
1838  // Allocate an executable page of memory.
1839  size_t actual_size;
1840  byte* buffer =
1841      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3,
1842                                      &actual_size,
1843                                      true));
1844  CHECK(buffer);
1845  HandleScope handles;
1846  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1847
1848  MacroAssembler* masm = &assembler;
1849  masm->set_allow_stub_calls(false);
1850  Label exit;
1851
1852  TestSmiShiftLeft(masm, &exit, 0x10, 0);
1853  TestSmiShiftLeft(masm, &exit, 0x50, 1);
1854  TestSmiShiftLeft(masm, &exit, 0x90, 127);
1855  TestSmiShiftLeft(masm, &exit, 0xD0, 65535);
1856  TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue);
1857  TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue);
1858  TestSmiShiftLeft(masm, &exit, 0x190, -1);
1859
1860  __ xor_(rax, rax);  // Success.
1861  __ bind(&exit);
1862  __ ret(0);
1863
1864  CodeDesc desc;
1865  masm->GetCode(&desc);
1866  // Call the function from C++.
1867  int result = FUNCTION_CAST<F0>(buffer)();
1868  CHECK_EQ(0, result);
1869}
1870
1871
1872void TestSmiShiftLogicalRight(MacroAssembler* masm,
1873                              Label* exit,
1874                              int id,
1875                              int x) {
1876  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1877  const int kNumShifts = 5;
1878  __ movl(rax, Immediate(id));
1879  for (int i = 0; i < kNumShifts; i++) {
1880    int shift = shifts[i];
1881    intptr_t result = static_cast<unsigned int>(x) >> shift;
1882    if (Smi::IsValid(result)) {
1883      __ Move(r8, Smi::FromInt(static_cast<int>(result)));
1884      __ Move(rcx, Smi::FromInt(x));
1885      __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit);
1886
1887      __ incq(rax);
1888      __ SmiCompare(r9, r8);
1889      __ j(not_equal, exit);
1890
1891      __ incq(rax);
1892      __ Move(rdx, Smi::FromInt(x));
1893      __ Move(rcx, Smi::FromInt(shift));
1894      __ SmiShiftLogicalRight(r9, rdx, rcx, exit);
1895
1896      __ incq(rax);
1897      __ SmiCompare(r9, r8);
1898      __ j(not_equal, exit);
1899
1900      __ incq(rax);
1901      __ Move(rdx, Smi::FromInt(x));
1902      __ Move(r11, Smi::FromInt(shift));
1903      __ SmiShiftLogicalRight(r9, rdx, r11, exit);
1904
1905      __ incq(rax);
1906      __ SmiCompare(r9, r8);
1907      __ j(not_equal, exit);
1908
1909      __ incq(rax);
1910    } else {
1911      // Cannot happen with long smis.
1912      Label fail_ok;
1913      __ Move(rcx, Smi::FromInt(x));
1914      __ movq(r11, rcx);
1915      __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok);
1916      __ jmp(exit);
1917      __ bind(&fail_ok);
1918
1919      __ incq(rax);
1920      __ SmiCompare(rcx, r11);
1921      __ j(not_equal, exit);
1922
1923      __ incq(rax);
1924      __ Move(r8, Smi::FromInt(shift));
1925      Label fail_ok3;
1926      __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3);
1927      __ jmp(exit);
1928      __ bind(&fail_ok3);
1929
1930      __ incq(rax);
1931      __ SmiCompare(rcx, r11);
1932      __ j(not_equal, exit);
1933
1934      __ addq(rax, Immediate(3));
1935    }
1936  }
1937}
1938
1939
1940TEST(SmiShiftLogicalRight) {
1941  // Allocate an executable page of memory.
1942  size_t actual_size;
1943  byte* buffer =
1944      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
1945                                      &actual_size,
1946                                      true));
1947  CHECK(buffer);
1948  HandleScope handles;
1949  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
1950
1951  MacroAssembler* masm = &assembler;
1952  masm->set_allow_stub_calls(false);
1953  Label exit;
1954
1955  TestSmiShiftLogicalRight(masm, &exit, 0x10, 0);
1956  TestSmiShiftLogicalRight(masm, &exit, 0x30, 1);
1957  TestSmiShiftLogicalRight(masm, &exit, 0x50, 127);
1958  TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535);
1959  TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue);
1960  TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue);
1961  TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1);
1962
1963  __ xor_(rax, rax);  // Success.
1964  __ bind(&exit);
1965  __ ret(0);
1966
1967  CodeDesc desc;
1968  masm->GetCode(&desc);
1969  // Call the function from C++.
1970  int result = FUNCTION_CAST<F0>(buffer)();
1971  CHECK_EQ(0, result);
1972}
1973
1974
1975void TestSmiShiftArithmeticRight(MacroAssembler* masm,
1976                                 Label* exit,
1977                                 int id,
1978                                 int x) {
1979  const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1};
1980  const int kNumShifts = 5;
1981  __ movl(rax, Immediate(id));
1982  for (int i = 0; i < kNumShifts; i++) {
1983    int shift = shifts[i];
1984    // Guaranteed arithmetic shift.
1985    int result = (x < 0) ? ~((~x) >> shift) : (x >> shift);
1986    __ Move(r8, Smi::FromInt(result));
1987    __ Move(rcx, Smi::FromInt(x));
1988    __ SmiShiftArithmeticRightConstant(rcx, rcx, shift);
1989
1990    __ SmiCompare(rcx, r8);
1991    __ j(not_equal, exit);
1992
1993    __ incq(rax);
1994    __ Move(rdx, Smi::FromInt(x));
1995    __ Move(r11, Smi::FromInt(shift));
1996    __ SmiShiftArithmeticRight(rdx, rdx, r11);
1997
1998    __ SmiCompare(rdx, r8);
1999    __ j(not_equal, exit);
2000
2001    __ incq(rax);
2002  }
2003}
2004
2005
2006TEST(SmiShiftArithmeticRight) {
2007  // Allocate an executable page of memory.
2008  size_t actual_size;
2009  byte* buffer =
2010      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
2011                                      &actual_size,
2012                                      true));
2013  CHECK(buffer);
2014  HandleScope handles;
2015  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
2016
2017  MacroAssembler* masm = &assembler;
2018  masm->set_allow_stub_calls(false);
2019  Label exit;
2020
2021  TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0);
2022  TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1);
2023  TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127);
2024  TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535);
2025  TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue);
2026  TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue);
2027  TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1);
2028
2029  __ xor_(rax, rax);  // Success.
2030  __ bind(&exit);
2031  __ ret(0);
2032
2033  CodeDesc desc;
2034  masm->GetCode(&desc);
2035  // Call the function from C++.
2036  int result = FUNCTION_CAST<F0>(buffer)();
2037  CHECK_EQ(0, result);
2038}
2039
2040
2041void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) {
2042  ASSERT(x >= 0);
2043  int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 };
2044  int power_count = 8;
2045  __ movl(rax, Immediate(id));
2046  for (int i = 0; i  < power_count; i++) {
2047    int power = powers[i];
2048    intptr_t result = static_cast<intptr_t>(x) << power;
2049    __ Set(r8, result);
2050    __ Move(rcx, Smi::FromInt(x));
2051    __ movq(r11, rcx);
2052    __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power);
2053    __ SmiCompare(rdx, r8);
2054    __ j(not_equal, exit);
2055    __ incq(rax);
2056    __ SmiCompare(r11, rcx);  // rcx unchanged.
2057    __ j(not_equal, exit);
2058    __ incq(rax);
2059    __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power);
2060    __ SmiCompare(rdx, r8);
2061    __ j(not_equal, exit);
2062    __ incq(rax);
2063  }
2064}
2065
2066
2067TEST(PositiveSmiTimesPowerOfTwoToInteger64) {
2068  // Allocate an executable page of memory.
2069  size_t actual_size;
2070  byte* buffer =
2071      static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2,
2072                                      &actual_size,
2073                                      true));
2074  CHECK(buffer);
2075  HandleScope handles;
2076  MacroAssembler assembler(buffer, static_cast<int>(actual_size));
2077
2078  MacroAssembler* masm = &assembler;
2079  masm->set_allow_stub_calls(false);
2080  Label exit;
2081
2082  TestPositiveSmiPowerUp(masm, &exit, 0x20, 0);
2083  TestPositiveSmiPowerUp(masm, &exit, 0x40, 1);
2084  TestPositiveSmiPowerUp(masm, &exit, 0x60, 127);
2085  TestPositiveSmiPowerUp(masm, &exit, 0x80, 128);
2086  TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255);
2087  TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256);
2088  TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535);
2089  TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536);
2090  TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue);
2091
2092  __ xor_(rax, rax);  // Success.
2093  __ bind(&exit);
2094  __ ret(0);
2095
2096  CodeDesc desc;
2097  masm->GetCode(&desc);
2098  // Call the function from C++.
2099  int result = FUNCTION_CAST<F0>(buffer)();
2100  CHECK_EQ(0, result);
2101}
2102
2103
2104#undef __
2105