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