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