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 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 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 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 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. 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 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). 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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