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 98 static void EntryCode(MacroAssembler* masm) { 99 // Smi constant register is callee save. 100 __ pushq(i::kRootRegister); 101 __ InitializeRootRegister(); 102 } 103 104 105 static void ExitCode(MacroAssembler* masm) { 106 __ popq(i::kRootRegister); 107 } 108 109 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 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. 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 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). 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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