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