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