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