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