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