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