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